理解逻辑式语言,必须先把程序设计语言的分类体系立起来。软考教材对程序设计语言的分类主要有两条线:一条按与计算机硬件结构的距离划分,分为机器语言、汇编语言和高级语言;另一条按程序设计范型划分,这是软考命题的富矿,也是本文的主线。程序设计范型指的是编写程序时采用的思维方式和组织代码的基本框架,它决定了程序员如何描述问题、如何组织计算。按范型划分,主流的程序设计语言可以归入四大阵营:命令式语言,以C语言、Pascal语言为代表,程序由一条条改变内存状态的指令组成,程序员必须显式地告诉计算机每一步做什么;面向对象语言,以Java语言、C++语言为代表,把数据和操作封装为对象,通过对象之间的消息传递完成计算;函数式语言,以LISP语言、Haskell语言为代表,把计算看作数学函数的求值过程,强调函数映射与不可变数据;逻辑式语言,以Prolog语言为代表,把计算看作逻辑推理过程,程序由描述问题的事实和规则组成,运行程序就是让推理机从事实和规则出发推导出结论。四大范式的划分依据,本质上是对"计算是什么"这一根本问题的不同回答:命令式回答状态改变,函数式回答函数映射,逻辑式回答逻辑推导,面向对象回答对象协作。
教材对逻辑式语言的正式表述是:以数理逻辑中的谓词演算为理论基础,程序由一组事实和一组规则组成,系统根据事实和规则通过模式匹配自动进行推理、得出结论的语言。这个定义里有三个必须拆开的构成要素。第一,理论基础:逻辑式语言不是泛泛地借用逻辑概念,而是直接建立在谓词逻辑这一形式系统之上,程序中的每一条语句都能对应到谓词逻辑的公式。第二,程序组成:逻辑式语言的程序不描述算法步骤,只描述知识本身,事实描述"什么为真",规则描述"在什么条件下可以推出什么"。第三,执行方式:程序不规定执行顺序,而是由内置的推理机制按照统一的推理策略自动搜索结论,其中模式匹配是推理过程中最核心的运算。理解这三要素,就抓住了逻辑式语言区别于其他三种范式的全部本质特征。
在软考中反复出现的一个几乎固定的出场方式是作为专家系统的开发语言。专家系统是人工智能领域的一种经典系统形态,它把某个专业领域专家的知识抽离出来,编码为知识库中的事实和规则,再由推理机根据用户提出的问题进行推理,给出专家级的结论。专家系统的核心部件与逻辑式语言的程序构成存在天然的同构关系:专家系统的知识库对应逻辑式程序中的事实和规则集合,专家系统的推理机对应逻辑式语言的推理机制,专家系统的用户提问对应逻辑式程序的查询目标。正因为这种结构上的同构,二十世纪七十年代以来,Prolog语言一直是构建专家系统原型的主流语言,大量经典专家系统都用Prolog语言或其变体开发。这段历史渊源正是软考命题人反复将"专家系统"与"逻辑式语言"捆绑出题的根本原因。
逻辑式语言的理论根基是谓词逻辑。命题逻辑只能处理完整的、不可再分的命题,表达能力有限;谓词逻辑在命题逻辑的基础上引入了个体、谓词和量词,能够表达"对任意个体,如果满足某条件则满足某结论"这类带变量的一般性规律。在逻辑式语言中,世界被建模为一组关系:个体用小写字母开头的常量表示,变量用大写字母开头的符号表示,关系用谓词描述。例如"父亲"是一个二元谓词,父亲(张伟,张三)表示张伟是张三的父亲,这是一条事实。谓词逻辑的公式经过规范化后,可以转化为Horn子句形式。Horn子句是至多包含一个肯定文字的子句,其标准形式是"结论 :- 条件一, 条件二",读作"如果条件一和条件二同时成立,则结论成立"。Horn子句恰好覆盖逻辑式程序所需的全部形态:没有条件部分的Horn子句就是事实,如"父亲(张伟,张三).";同时有结论部分和条件部分的Horn子句就是规则,如"祖父(X,Y) :- 父亲(X,Z), 父亲(Z,Y).",表示如果Z是Y的父亲且X是Z的父亲,则X是Y的祖父。把谓词逻辑公式规范化为Horn子句,是逻辑式语言能被机器高效推理的关键一步,Horn子句在表达能力与推理效率之间取得的平衡,正是逻辑式语言工程可行性的来源。
"模式匹配"是软考逻辑式语言考题中最核心的关键词,它在逻辑式语言中有严格的数学含义,即合一运算。合一要回答的问题是:给定两个包含变量的项,是否存在一组变量赋值,使得两个项完全相同。例如,项"父亲(X,张三)"与项"父亲(张伟,Y)"可以合一,只需令X取张伟、Y取张三;而项"父亲(张伟,张三)"与"母亲(张伟,张三)"则无法合一,因为谓词符号本身不同。合一算法递归地比较两个项的结构:常量与常量比较要求字面相同;变量与任意项比较即可成功,同时建立变量绑定;复合项要求谓词符号相同、参数个数相同,且对应位置的参数逐一两两合一。逻辑式语言的推理机执行规则时,就是不断进行合一运算:把查询目标与程序中的规则头合一,若成功则产生变量的绑定,进而用绑定后的规则体替换原目标。合一的本质是一种约束求解,它把"这个条件是否成立"的问题转化为"是否存在一组变量取值使两边结构相同"的方程求解问题,这正是逻辑式语言宣称的模式匹配与普通编程语言中条件判断的本质区别——条件判断只比较已知的值,合一则为变量寻找未知的值。
合一解决了单步匹配问题,但当程序中存在多条可匹配的规则或事实时,推理机必须决定试哪一条、失败后怎么办。逻辑式语言采用深度优先搜索加回溯的策略。推理机按照程序文本的顺序依次尝试每一条子句,每尝试一条就记录一个选择点;如果某条路径最终推导失败,推理机就回到最近的选择点,撤销已做的变量绑定,换下一条子句继续尝试。回溯机制使得逻辑式程序天然具备多解能力:同一个查询可以依次求出所有满足条件的解,不需要程序员编写任何循环或递归结构。例如对查询"祖父(X,张三)",推理机先匹配出所有满足"父亲(Z,张三)"的Z,再对每个Z回溯寻找满足"父亲(X,Z)"的X,最终枚举出全部祖父。控制流从程序员手中移交给了推理机,这是逻辑式语言与命令式语言最深刻的分野:命令式程序员要设计循环、维护游标、处理边界条件,逻辑式程序员只需描述关系。理解回溯,才能真正理解逻辑式程序为何写得异常简短,也才能理解它在纯推理任务上表现优异、在强计算任务上效率不足的原因。
逻辑式语言家族中最核心的成员是Prolog语言,1972年前后在法国马赛诞生,其名称是"逻辑编程"的法语缩写。Prolog语言确立了逻辑式语言的经典三要素:事实、规则、查询,并内置了合一与回溯推理机,此后数十年一直是逻辑式语言的标杆。在Prolog语言的基础上,衍生出了多个重要变体:Datalog语言是一种受限的逻辑式语言,禁止复合项,保证了查询必然终止,被广泛用于数据库的演绎查询引擎和程序静态分析中,许多大型软件系统的权限验证和指针分析工具都基于Datalog语言实现;Mercury语言给逻辑式语言加入了强类型系统和模式系统,大幅提升了运行效率,定位于高可靠应用开发;lambda-Prolog语言则把高阶逻辑引入逻辑式编程,支持把谓词作为参数传递。从这一家族谱系可以看出,逻辑式语言并非只有教学意义,它在数据库、程序分析、定理证明等领域至今不可替代,软考将其列为四大范式之一,背后是对真实技术版图的准确反映。
专家系统的经典结构包括知识库、推理机、解释器和用户界面四部分,其中知识库和推理机与逻辑式语言的程序模型完全对应。知识库中的事实对应逻辑式程序的事实子句,产生式规则对应规则子句,推理机按照正向推理或反向推理策略工作:正向推理从已知事实出发反复应用规则推出新事实,反向推理从目标结论出发反向寻找支持证据。逻辑式语言的推理机天然支持反向推理,用户提交查询目标,系统逐层展开规则直至触及事实。这种深度绑定决定了软考的命题形态:题目只要出现"描述事实和规则""模式匹配""推理得出结论"等特征描述,答案几乎必然指向逻辑式语言。需要辨析的是,专家系统并不只能用逻辑式语言开发,用Java语言或C++语言同样可以实现产生式推理,但那些语言需要程序员自己编写推理机,而逻辑式语言把推理机作为语言本身的一部分提供,两者在"开发方式"上存在本质差异,这正是考题表述中"描述事实和规则由模式匹配得出结论"所强调的要点。
逻辑式语言的适用场景集中在符号推理密集的领域。第一类是定理证明与形式验证,逻辑式语言与形式逻辑的同源性使其成为机器证明工具的天然选择,硬件电路的形式化验证、程序正确性证明工具都大量借鉴逻辑式编程思想。第二类是自然语言处理中的语法分析,用规则描述文法约束、用合一完成句法结构匹配,与逻辑式语言的工作方式完全一致。第三类是数据库的演绎查询,Datalog语言在这
本篇完!