编程范型[方法论]
编程范型、编程范式或程序设计法[Programming paradigm]
定义:决定了程序员对程序执行的看法。
一种语言可能支持多种编程范式,编程的时候开发一个程序中可能使用到多种范式
0x01: 指令式 : 一种描述电脑所需作出的行为的编程典范。
大部分的编程语言都是指令式的。
很多指令式编程语言都是汇编语言的抽象化
指令式派生范式
过程式【过程化编程】:主要要采取过程调用或函数调用的方式来进行流程控制。
对指令式的封装,颗粒变大
流程则由包涵一系列运算步骤的过程(Procedures),例程(routines),子程序(subroutines), 方法(methods),或函数(functions)来控制。
在程序执行的任何一个时间点,都可以调用某个特定的程序。任何一个特定的程序,也能被任意一个程序或是它自己本身调用。
块结构: 块或代码块是将源代码组织在一起的词法结构。块构成自一个或多个声明和语句。
代码块
结构化: 采用子程序、块结构、for循环以及while循环等结构取代传统的got0。
改善计算机程序的明晰性、质量以及开发时间,并且避免写出面条条式代码
模块化编程 : 强调计算机程序的功能分离独立的、可相互改变的模块的软件技术, 使得每个模块都包含着执行预期功能的一个唯一方面所必须得所有东西。
指令式 —— 过程式 —— 快结构 —— 结构化 —— 模块化
对指令的封装颗粒越来越大, 一个单元的功能性越来越强,但是强调的是业务性的单一。
0x01面向对象 [Object-oriented programming (OOP)]
一种程序开发抽象具有对象概念的编程典范。
可包含 数据、特性、代码与方法。
对象:则是类的实例, 是作为程序的基本单元。
面向对象程序设计可以看作一种在程序中包含各种独立而又互相调用的对象的思想,这与传统的思想刚好相反:传统的程序设计主张将程序看作一系列函数的集合,或者直接就是一系列对电脑下达的指令。
分享非面向对象程序前身语言
OC/C++ 都分享了C语言的基础钙奶
面向对象程序设计通常共享高端编程语言的低端功能。
变量 能存储一些内置类型的信息如整数与字符,也有些是数据结构像是字符串、串列与散列表等包含内置或复合的变量如指针。
程序:也称为函数、方法或例程,是指输入数据产生输出结果,现代语言还包含结构化编程结构如程序循环与条件。
类与对象
类(Class): 定义了一件事物的抽象特点。 类包含数据的形式以及对数据的操作 【静态】
对象: 类的实例(Instance) 【动态】
语言: C++
动态配置与消息传递机制:
定义上动态配置是指方法会随着实例动态的改变。而消息传递机制(Message Passing)是指一个对象通过接受消息、处理消息、传出消息或使用其他类的方法来实现一定功能。
面向对象的三大特性:
封装
:通过有限制只有特定类的对象可以访问这一特定类的成员, 而它们通常利用接口实现消息传入传出。
面向对象程序设计隐藏了某一方法的具体执行步骤,取而代之的是通过消息传递机制发送消息给它。
继承
:在某种情况下,一个类会有子类。 子类比原来的类更加具体化。
多态
: 由于继承而产生的相关的不同的类,其对象对同一消息回做出不同的响应。
更多的特性;
抽象性:
简化复杂的现实问题的途径,它可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。 常见的抽象类。
基于类编程(面向类) 【C++】 类+接口
面向对象编程的一种风格,在程序设计时,强调对象(object)的类别(class)
一个对象必须基于类别才能够创造出来(这个和重试对象本事是基于原型编程的差异)
实例之间的差异性只有状态。
稳定性高,安全性比较高。
修改、更新类别结构与行为、引用旧类别的程序都需要同步修改。
基于原型编程 [Javascript]
在原型编程中,行为重用(在基于类的语言通常称为继承),是通过复制已经存在的原型对象的过程实现的。
这个模型一般被认为是无类的、面向原型、或者是基于实例的编程。
批评: 通常担心的是正确性、安全性、可预测性以及效率。
基于类VS基于原型
基于类
:类 + 接口 【数据结构+ 行为】
1)提倡使用一个关注分类和类之间关系的开发模型。
2)从现存类继承,从而创建一种层级, 不提倡运行时原型的修改
3)绝大多数是基于编译型 和 静态类型程序语言
4)构造: 一个新的历史通过类构造器和给构造器的可选的参数来构造。
5)委托: 基于类和接口的关系
6)结构: 整理类的结构
基于原型
: 原型对象
1)提倡关注一系列对象实例的行为,而之后才关心如何将这些对象划分到最近的使用方式相似的原型对象, 而不是分成类。
2)提倡运行时原型的修改。
3)绝大多数基于原型的系统,是基于解释型
的和动态类型程序语言
。
4)构造: 没有显示的类, 对象直接通过一个原型属性从其他对象进行集成。js中叫做prototype。 构造方式两种(1) 复制已有的对象 (2)通过扩展空(nihilo)对象创建。 【注意protoType 是复制作用, 所以对原型不会有副作用】
5)委托:运行时语言可以仅仅通过循着一个序列的指针直到找到匹配这样的方式
,来定位属性或者寻找正确的数据。所有这些创建行为共享的行为需要的是委托指针
。
6)结构:子对象随着时间可能被继续修改,但是对原型对象没有副作用。 子对象的数据和方法都可被修改,一次, 一些基于原型的语言吧数据和方法二者合称为‘槽’(slot)。
7)串接: 属性和方法被原样复制
1)子对象从原型对象中分裂出来,修改不会影响到原型对象
2)需要遍历整个委托链才可以判定不存在
3)js中的父原型数据修改,如果子对象没有改过,就会影响到子对象,如果改过,就不会影响。
4)可能会一定程度上浪费内存,而js中的拷贝时机的原因,节省了一些内存。
契约式设计【Design by Contract,缩写 DbC】
定义
: 为软件组织定义正式的,精确的并且可验证的接口。 从而能够为传统的抽象数据类型有增加了先验条件、后验条件 和不变式。
主要针对代码的合理性的验证等等。
面向切面的程序设计 【aspect-oriented programming (AOP)】
旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度
通过在现有代码基础上增加额外的通知(Advice)机制,能够对被声明为“切点(Pointcut)”的代码块进行统一管理与装饰,
比如说:“对所有方法名以
set*
开头的方法添加后台日志”。该思想使得开发人员能够将与代码核心业务逻辑关系不那么密切的功能(如日志功能)添加至程序中,同时又不降低业务代码的可读性。面向切面的程序设计思想也是面向切面软件开发的基础。
横切点: 可以理解为何主要业务没有直接关系的,是主页的一个副业务。
将代码逻辑切分为不同的模块(即关注点:一段特定的逻辑功能)
几乎所有的编程思想都涉及代码功能的分类,将各个关注点(Concern)封装成独立的抽象模块(如函数、过程、模块、类以及方法等),又可供进一步实现、封装和重写.
部分关注点“横切”程序代码中的数个模块,即在多个模块中都有出现,它们即被称作横切关注点。 日志功能就是一个典型
下面这个内容需要进一步去理解一下
切面的概念源于对面向对象的程序设计和计算反射的融合。面向切面编程语言拥有很多类似于元对象协议的功能,但有更多的限制。切面相关的编程概念包括主题、混入和委托。使用面向切面思想的其他方式有复合过滤器和Hyper/J的hyperslices方式。
看到连接点模型
函数式编程
函数式编程,或称函数程序设计、泛函编程(Functional programming)
是一种编程范式,它将电脑运算视为函数运算,并且避免使用程序状态以及易变对象。 [没有程序状态、 没有容变对象]
λ演算为该语言最重要的基础。而且,λ演算的函数可以接受函数作为输入参数和输出返回值。
比起指令式编程,函数式编程更加
强调程序执行的结果而非执行的过程
,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。
在函数式编程中,函数是头等对象,意思是说一个函数,既可以作为其它函数的输入参数值,也可以从函数中返回值,被修改或者被分配给一个变量。
典型的函数式编程语言
纯函数式编程语言
通常不允许直接使用程序状态以及可变对象,典型语言有:Miranda、Haskell和Idris等。
静态类型语言
:ML家族的Standard ML、OCaml、F#,还有Scala、Typed Racket[25]等。
动态类型语言
:Lisp家族的Scheme、Common Lisp、Clojure、Racket,还有LOGO、Erlang、Wolfram语言和R等。
其他特殊风格的函数式编程语言有:APL/J和XSLT等。
头等函数
函数作为头等公民。 函数可以作为
别的函数的
参数
、函数的返回值
,赋值给变量
或存储在数据结构中
。
有人主张应包括支持
匿名函数
(函数字面量,function literals)。在这样的语言中,函数的名字没有特殊含义,它们被当作具有函数类型的普通的变量对待。
头等函数是函数式程序设计所必须的。通常要使用高阶函数。map函数就是一个高阶函数,其实参是一个函数及一个list,返回结果是把作为参数的函数作用于list的每个元素后的结果形成的list。
把函数作为函数参数与函数返回值会遇到特别的困难。
【特别是存在非局部变量与嵌套函数、匿名函数。】
早期的指令式编程语言,或者不支持函数作为结果类型(如ALGOL 60, Pascal),或者忽略嵌套函数与非局部变量(如C语言)。
早期的函数式语言Lisp采取了动态作用域方法,把非局部变量绑定到函数执行点最近的变量定义。Scheme语言支持词法作用域的头等函数,把对函数的引用绑定到闭包(closure)而不是函数指针,这使得垃圾收集成为必须。
比较把函数视作头等公民的典型的函数式语言Haskell与把函数视作二等公民的指令式编程的C语言的有关概念。
高阶函数:
具有函数参数的函数。
引用相等来判断两个函数是否相等,即为同一个函数引用没有匿名函数的时候,函数只能使用函数指针来表示。
纯函数式编程
将所有计算都当作数学函数的求值(evaluation)
纯函数式编程还可以定义为禁用状态变更和可变数据。
纯函数式编程主要在于确保函数遵守函数式范型,只依赖于它们的实际参数,而不用管任何全局或局部的状态。
纯函数式数据结构必然是持久性数据结构。持久性是函数式编程所要求的,如果没有它,相同的计算就可能返回不同的结果。函数式编程可以使用非纯函数式的持久性数据结构,比如持久性数组,而这些数据结构不可以用在纯函数式程序中。
纯粹采用函数式编程的基础部件(如map、reduce、filter等),进行响应式编程(异步数据流程编程)的编程范型,被称为
函数式响应式编程
。
函数级编程(Function-level)
将程序作为数学对象来研讨
函数级程序是无变量(variable-free)
的,也叫无点编程
,因为程序变量在函数级程序中是不需要的,而它在值级定义中是根本性的。
和它对立编程范型: 值级编程(value-level)
值级程序是描述如何组合各种“值”(比如数、符号、字符串等),形成其他的值直到获得最终的“结果值”的程序。
通过应用各种从值到值的函数比如加法、串接、逆矩阵等,从现存的值构造新的值。
元编程
编写或操纵其它程序(或者自身)作为它们的资料,或者在编译时完成部分本应在运行时完成的工作
多数情况下,与手工编写全部代码相比,程序员可以获得更高的工作效率,或者给与程序更大的灵活度去处理新的情形而无需重新编译。
编写源程序的语言称之为
源语言
。 被操纵的程序的语言称之为“目标语言
”。 一门编程语言同时也是自身的元语言的能力称之为“反射
” 或“自反
”。
内省
【type introspection】(或称“自省”)机制仅指程序在运行时对自身信息(称为元数据)的检测;
反射
机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构。
反射是促进元编程的一种很有价值的语言特性。把编程语言自身作为一级数据类型(如LISP、Forth或Rebol)也很有用。支持
泛型编程
的语言也使用元编程能力。
元编程通常通过两种方式实现。
1)是通过应用程序编程接口
(APIs)将运行时引擎的内部信息暴露于编程代码。
2)是动态执行包含编程命令的字符串表达式
。因此,“程序能够编写程序”。虽然两种方式都能用于同一种语言,但大多数语言趋向于偏向其中一种。
- 产生式编程 —— 生成代码
- 在运行时改变或者可以使用增量编译,就可以在不实际生成源代码的情况下使用这种技术实现元编程。
常见的元编程工具就是:
编译器
自产生程序是一种源代码等于输出的特殊的元程序。面向语言的程序设计是一种强烈关注元编程的编程风格,通过领域特定语言来实现。
宏【Macro】
根据一系列预定义的规则替换一定的文本模式。
解释器或编译器在遇到宏时会自动进行这一模式替换。对于编译语言,宏展开在编译时发生,进行宏展开的工具常被称为宏展开器
。宏包括键盘宏和宏语言。
绝大多数情况下,“宏”这个词的使用暗示着将小命令或动作转化为一系列指令。
宏的用途在于自动化频繁使用的序列或者是获得一种更强大的抽象能力。
C语言的宏预处理器的工作只是进行简单的文本搜索和替换,使用附加的文本处理语言如M4,C程序员可以获得更精巧的宏。
宏应用
应用程序也可以使用一种和宏类似机理的系统来允许用户将一系列(一般是最常使用到的操作)自定义为一个步骤。也就是用户执行一系列操作,并且让应用程序来“记住”这些操作以及顺序。更高级的用户可以通过内建的宏编程来直接使用那些应用程序的功能。
当使用一种不熟悉的宏语言来编程时,比较有效的方法就是
记录一连串用户希望得到的操作,然后通过阅读应用程序记录下来的宏文件来理解宏命令的结构组成
。
宏语言是一类编程语言,其全部或多数计算是由扩展宏完成的。宏语言并未在通用编程中广泛使用,
但在文本处理程序中应用普遍
。C预处理器
M4
Java
模板元编程 【Template metaprogramming,缩写:TMP】
编译器使用模板产生暂时性的源码, 然后再和剩下的源码混合并编译。
1)模板的输出包括:编译时期的常量、数据结构以及完整的函数。
- 如此利用模板,可以被想成编译期的执行
构成要素:
1)模板必须被定义
: 模板的定义描述了生成源码的一般形式
2)定义的模板必须被实体化才行
:实体化则导致了某些源码的组合根据该模板而生成。
相比于模板,宏的
缺点
:
宏只不过是以文字的操作及替换来生成代码,虽然同为编译期的语言特色,但宏系统通常其编译期处理流的能力(compile-time process flow abilities)有限,且对其所依附之语言的语义及类型系统缺乏认知
模板元编程没有可变的变量,变量一旦初始化后就不能够改动。因此他可以被视为
函数式编程
(functional programming)的一种形式。
用途:
一些使用模板元编程的共同理由是为了实现泛型编程(generic programing)
或是展现自动编译期优化
,像是只要在编译期做某些事一次就好, 而无需每次成功需执行时去做。
编译期类别生成
:编译器必须在编译期知道模板的参数值。通过值知道对应的类别。
编译期初代优化
:
编译期循环展开(loop-unrolling)是一个更显著的例子,模板元编程可以被用来产生n维(n-dimensional)的向量类别(当然n必须在编译期已知)。与传统n维向量比较,他的好处是循环可以被展开,这可以使性能大幅度提升。
静态多态
多态是一项共同的标准编程工具,派生类的对象可以被当做基类的对象使用,但能够调用派生对象的函数、方法(methods)。
动态多态
问题: 会让在执行的时候通过虚拟表来查找执行的方法,无法避免运行时的消耗。
静态多态
:成员函数的本体在被他们的宣告之前都不会被实体化,而且它可利用 static_cast 并透过自己的函数来使用派生类的成员,所以能够在编译时产生出带有多态特性的对象复合物。
反射式编程
计算器程序在运行时可以
访问
、检测
和修改
它本身状态或行为的一种能力。
内省
【type introspection】(或称“自省”)机制仅指程序在运行时对自身信息(称为元数据)的检测;
反射
机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构。
反射的主要用途:
使用给定的程序,动态地适应不同的运行情况
。
利用面向对象建模中的多态(多态性)也可以简化编写分别适用于多种不同情形的功能代码,但是反射可以解决多态(多态性)并不适用的更普遍情形,从而更大程度地避免硬编码
(即把代码的细节“写死”,缺乏灵活性)的代码风格。
反射也是元编程的一个关键策略。
同像性
同像性(homo iconicity):它意味着
一个程序的结构与其句法是相似的
,因此易于通过阅读程序来推测程序的内在涵义。
1)如果一门编程语言具备了同像性,说明该语言的文本表示(通常指源代码),与其抽象语法树(AST)具有相同的结构(即AST和语法是同形的)。
2)该特性允许使用相同的表示语法,将语言中的所有代码当成数据,来存取以及转换,提供了“代码即数据”的理论前提。
优点
: 同像性的一个优点是,以新概念扩展语言通常变得更简单,因为表示代码的资料,可在程序的元和基本层之间传递。函数的抽象语法树,可以作为元层中的数据结构来组成和操作,然后被评估。它可以更容易理解如何操作代码,因为它可以被理解为简单的资料(语言本身的格式亦同为资料格式)。
缺点
: 有人认为至少在类似LISP的列表导向的语言的情况下,它会消除许多能帮助人们分析语言结构的视觉线索,而可能导致陡峭的学习曲线.
元对象
[MetaObject]
定义
:操纵、创建、描述或实现对象(包括自身)的对象.
元对象可以定义的一些信息包括: 基础对象的类型、接口、类、方法、特性、解析树等。
元对象是计算机科学反射概念的例子,这里的系统(通常在运行时间)能访问它自己的内部结构。反射在根本上确使一个系统能现场重写自身,在其运行时改变自己的实现。
元对象协议
【MOP : metaproject protocol】
提供了访问和操纵对象系统的结构和行为的词汇表。
元对象协议的典型功能包括:
1)创建或删除一个新类
2)创建一个新属性或方法
3)致使一个类继承自一个不同的类(变更类结构)
4)产生或变更定义一个类的方法的代码。
元对象协议不知是到底层实现的接口,转而, 通过原对象协议,对象系统是依据元对象系统而递归实现的。 它自身的理论上是依据
元--元
对象系统来实现的,以此类推直到任意一个基础情况
(对象系统的一个一致性状态)被确定,协议就自身而言,是在这些实现层级之间的递归泛函联系。
元对象协议
和开闭原则
是对立的
运行时间和编译时间
在于运行时间不能获得编译的时候,元对象协议的实现就有额外的复杂性。
例如,有可能通过这种协议变更类型层级,但是这么做可能导致,用可替代类模型定义编译的代码出问题。一些环境找到了有创意的解决方法,比如通过在编译时间处理元对象问题。
用途:
1) 定义元对象
2)用于软件工程应用中,用来表示和操纵设计工件
3)实现面向切面编程的一种方式。
面向特性编程
面向特性编程(@OP)是一种程序层面的标记技术。编程者可以给程序元素(例如类和方法)标记上特性,来指示它们包含特定于应用或特定于领域的语义。
特性将一个应用的核心逻辑(或业务逻辑)同特定于应用或特定于领域的语义(比如日志和网页服务功能)分离开来。
面向语言的程序设计
面向语言的程序设计(Language-Oriented Programming,LOP),将有相同状态的块建造成对象、模块和构件,不再用通用编程语言解决问题,程序员首先为问题编写一种或多种领域特定语言
,然后再在这些语言中解决问题。
这个概念使用用户词汇来获得需求,然后创造一门与用户描述尽可能一致的实现语言,这样从需求到实现的映射会非常直接。
判断“一致性”的方法是这门语言的“重复度”,即当需求有一次独立变动时需要做多少次修改操作。它并不假定什么是实现新语言的最好语言,相反,开发者可以通过对信息流的分析做不同选择。
觉得实现语法糖也是一种面向语言的程序设计, eg: Typescript就是对javascript语言的设计类似,我们针对一些特性设置一些工具或者开发一个领域语言。
数据流程编程
它将程序建模为数据在运算(operation)之间流动的有向图,从而实现了数据流程原理和架构。
数据流程编程语言,共享了纯函数式语言的某些特征,比如单赋值,并且开发它们的动因,通常是为了向更适合数值处理的语言,增加函数式编程概念。
最初开发更常规的数据流程语言,是为了使并行编程
更加容易。
为了避免混淆与数据流程计算或数据流程架构,它基于了非确定型机器泛型, 常用“数据流(data stream) ”代替 “数据流程”
—— 这里还是有点不太理解的地方, 看看以后这里要怎么处理吧。
管道
散列表
是数据流程的关键。
同步式编程 【synchronous】
这里的响应式只得是大的系统,即为项目,而不是响应式架构
同步式响应式编程
(SRP) , 也是为响应式系统编程而优化的一种计算机编程泛型。
同步式编程的原理是对编程语言做同步抽象,使之同样于在数字电路中的那种同步抽象。
响应式编程【Reactive Programming】
一种面向数据流和变化传播的声明式编程范式。
这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。
应式编程最初是为了简化交互式用户界面的创建和实时系统动画的绘制而提出来的一种方法,但它本质上是一种通用的编程范式。
例如,在MVC软件架构中,响应式编程允许将相关模型的变化自动反映到视图上,反之亦然。
响应式编程范型基于同步数据流程编程范型,但是放松了实时限制。响应式编程范型介入了表示连续时变值的行为(behaviour),和表示离散值的事件。
函数式响应式编程 (FRP)
它采用函数式编程的基础部件(如map、reduce、filter等),进行响应式编程(异步数据流程编程)。
FRP的形式
- 其多样性的一条轴线,是离散与连续语义对比。
- 另一条轴线,是怎样让FRP系统可以动态地更改。
流处理
相当于数据流编程, 事件流处理, 和反应式编程, 起允许一些应用更容易地利用了有限形式的
并发处理
。
这些应用程序可以使用
多个计算单元
,例如图形处理上的浮点运算器或现场可编程门数组(FPGAs),而无需明确管理这些单元之间的分配,同步或通信。
基于流程编程 (flow-based) FBP
它将应用黑箱进程的网络,它们经过预先定义的连接,通过消息传递来交换数据,而这里的连接是在“外部”指定给进程的。这些黑箱进程不需要更改内部,就可以无尽的重新连接而形成不同的应用。FBP因而是天然基于构件的。
FBP是一种特殊形式的数据流程编程,它基于了有界缓冲区,带有确定生存时间的信息包,命名端口,和独立的连接的定义。
数据驱动编程
在其中程序语句描述要匹配的数据,和对它需要做的处理,程序本身不定义选取数据的一序列文件操作步骤。
数据驱动语言的标准例子是
文本处理语言sed
和AWK
,在其中数据是输入流中的一序列的行,因而它们也叫面向行的语言,而模式匹配主要通过正则表达式或行号来完成。
适配抽象数据类型设计方法到面向对象编程,导致数据驱动设计。在面向对象编程中,这种类型的设计有时被用于在构思一段软件期间定义类。
事件驱动程序设计
这种模型的程序执行流程是由用户的动作(如鼠标的按键,键盘的按键动作)或者是由其他程序的消息来决定的。
相对于批处理程序设计(batch programming)而言,程序执行的流程是由程序员来决定。批处理(batch)的程序设计在初级程序设计教学课程上是一种方式。然而,事件驱动程序设计这种设计模型是在交互程序(Interactive program)的情况下孕育而生的。
取代传统上一次等待一个完整的指令然后再做执行的方式,事件驱动程序模型下的系统,基本上的架构是预先设计一个事件循环所形成的程序,这个事件循环程序不断地检查目前要处理的信息,根据要处理的信息执行一个触发函数进行必要的处理。其中这个外部信息可能来自一个目录夹中的文件,可能来自键盘或鼠标的动作,或者是一个时间事件。
声明式编程 【Declarative programming】
是对与命令式编程不同的编程范型的一种合称。它们建造计算机程序的结构和元素,表达计算的逻辑而不用描述它的控制流程
通常被定义为除命令式以外的任何编程范型
常见的声明式语言: 数据库查询语言如SQL的查询子集和XQuery,正则表达式,配置管理系统如Puppet管理配置语言。
声明式领域专属语言(DSL)还包括:yacc语法解析器,编译说明语言Make等。DSL不需要是图灵完全的,往往容易以一种纯声明式的方式来表达。很多文本标记语言例如HTML、MXML、XAML和XSLT往往是声明式的。
- 告诉计算机需要计算“什么”而不是“如何”去计算的高级程序。
- 明确的对应数理逻辑的编程语言。
- 任何没有副作用的编程语言,或者更确切一点,任何参照透明的编程语言。
逻辑式编程
逻辑编程通常被看做是形式逻辑的理论,把计算看做推导,透过函数、推理规则或重写规则,来描述变量之间的关系。它的语言执行器(编译器或解释器)采用了一个固定的算法,以从这些关系产生结果。作为典型代表的Prolog语言,声明关系并且对关系进行提问;它和许多逻辑编程语言,都允许副作用的存在。
函数式编程
数式编程,尝试最小化状态带来的副作用,因此可以被归类入声明式编程,它现在因大幅简化了并行计算的编写难度而备受关注。除了纯函数式编程语言如Haskell,多数函数式编程语言如Scheme、Clojure、OCaml、Standard ML等,允许副作用的存在。
约束式编程
在约束式编程中,变量之间的关系是在约束中说明的,定义了问题的解的范围。这些约束然后被应用程序来求解,以使得每个变量获得一个值,并让最多的约束得到满足。约束式编程经常被用作函数式编程、逻辑编程甚至命令式编程的补充,用来解决人工智能中的约束满足问题。
逻辑编程 [inductive logic programming]
它设置答案须符合的规则来解决问题,而非设置步骤来解决问题。
算法=逻辑+控制
逻辑提供了一个证明问题是真还是假的方法。创建证明的方法是人所皆知的,故逻辑是解答问题的可靠方法。逻辑编程系统则自动化了这个程序。人工智能在逻辑编程的发展中发挥了重要的影响。
常用到逻辑编程工具的范畴:
最常用的逻辑编程语言是Prolog,另外有较适用于大型方案的Mercury。
回答集编程
类似传统逻辑编程而语义上密切于非单调逻辑的一种声明式编程
区别:
在传统逻辑编程中,否定为失败指示推导失败;
在回答集编程中,它指示一个文字的一致性。
约束编程【Constraint programming】
变量之间的“关系”是以约束的形式陈述(组织)的。这些“关系(约束)”和命令式编程语言元素不同的是:它们并非明确说明了要去执行的步骤中的某一步,而是规范其解的一些属性。约束编程是一种声明式编程。
查询语言 【Data Query Language, DQL】
是用于从数据库或信息系统中查询数据的计算机语言 , eg: SQL
本体语言
在计算机科学和人工智能领域,本体语言(ontology language、又称为本体论语言)是指用于构建本体的形式语言。此类语言允许对有关特定领域的知识加以编码,且常常还包括为处理这些知识提供支持的推理规则。本体语言通常为声明式语言(又称为表述型语言、说明性语言),几乎总是属于框架语言的泛化形式,且一般都基于一阶逻辑或描述逻辑。