Prolog 的程序
Prolog 程序一般由一组事实、规则和问题组成.问题是程序执行的起点,称为程序的目标.
我们首先写出一个 Prolog 的程序,如下:(为引用方便起见,我们把这个程序成为“程序0”)
likes(bell, sports).
likes(mary, music).
likes(mary, sports).
likes(jane, smith).
friend(john, X):- likes(X, reading), likes(X, music).
friend(john, X) :- likes(X, sports), likes(X, music). ?- friend(john, Y).
接下来我们分析一下这个程序:
可以看出,这个程序中有四个事实、两条规则和一个问题.其中事实、规则和问题都分行书写;规则和事实可连续排列在一起,其顺序可随意安排,但同一谓词名的事实或规则必须集中排列在一起;问题不能与规则及事实排在一起,它作为程序的目标要么单独列出,要么在程序运行时临时给出.
这个程序的事实描述了一些对象(包括人和事物)间的关系;而规则则描述了 John 交朋友的条件,即如果一个人喜欢读书并且喜欢音乐(或者喜欢运动和喜欢音乐),那么这个人就是 John 的朋友(当然,这个规则也可看做 John 朋友的定义);程序中的问题是“约翰的朋友是谁?”
Prolog 程序中的目标还可以变化,也可以含有多个语句(上例中只有一个).如果有多个语句,则这些语句称为子目标.例如对上面的程序,其问题也可以是:
?-likes(mary, X).
或 ?-likes(mary, music).
或 ?-friend(X, Y).
或 ?-likes(bell, sports), likes(mary, music), friend(john, X).
等.但对于不同的问题,程序运行的结果一般是不一样的.
还需说明的是,Prolog程序中的事实或规则一般称为它们对应谓词的子句.例如,上面程序中的前4句都是谓词 likes 的子句. Prolog 规定,同一谓词的子句应排在一起.从语句形式和程序组成来看, Prolog 就是一种基于 Horn 子句的逻辑程序.这种程序要求用事实和规则来求证询问,即证明所给出的条件子句和无条件子句与目标子句是矛盾的,或者说程序中的子句集是不可满足的.这就是所谓的 Prolog 的说明性语义.
从 Prolog 的语句来看, Prolog 语言的文法结构相当简单.但由于它的语句是 Horn 子句,而 Horn 子句的描述能力是很强的,所以 Prolog 的描述能力也是很强的.例如,当它的事实和规则描述的是某一学科的公理,那么问题就是待证的命题;当事实和规则描述的是某些数据和关系,那么问题就是数据查询语句;当事实和规则描述的是某领域的知识,那么问题就是利用这些知识求解的问题;当事实和规则描述的是某初始状态和状态变化规律,那么问题就是目标状态.所以, Prolog 语言实际是一种应用相当广泛的智能程序设计语言.从上面最后一个目标可以看出,同过程性语言相比,对于一个 Prolog 程序,其问题就相当于主程序,其规则就相当于子程序,而其事实就相当于数据.
Prolog 程序的运行机理
要想了解 Prolog 的运行机理,首先需要了解几个基本概念.
1、自由变量与约束变量
Prolog中把无值的变量称为自由变量,有值的变量称为约束变量.一个变量取了某值就说该变量约束于某值,或者说该变量被某值所约束,或者说该变量被某值实例化了.在程序运行期间,一个自由变量可以被实例化而成为约束变量,反之,一个约束变量也可被解除其值而成为自由变量.
2、匹配合一
两个谓词可匹配合一,是指两个谓词的名相同,参量项的个数相同,参量类型对应相同,并且对应参量项还满足下列条件之一.
如果两个都是常量,则必须完全相同.
如果两个都是约束变量,则两个约束值必须相同.
如果其中一个是常量,一个是约束变量,则约東值与常量必须相同.
至少有一个是自由变量.
例如下面的两个谓词:
prel(“ob1”, “ob2”, Z)
prel(“ob1”, X, Y)
只有当变量 X 被约束为”ob2”,且 Y、Z 的约束值相同或者至少有一个是自由变量时,它们才是匹配合一的.
Prolog 的匹配合一,与归结原理中的合一的意思基本一样,但这里的合一同时也是一种操作.这种操作可使两个能匹配的谓词合一起来,即为参加匹配的自由变量和常量,或者两个自由变量建立一种对应关系,使得常量作为对应变量的约束值,使得两个对应的自由变量始终保持一致,即若其中一个被某值约束,则另一个也被同一值约束;反之,若其中一个的值被解除,则另一个的值也被解除.
3、回溯
所谓回溯,就是在程序运行期间,当某一个子目标不能满足(即谓词匹配失败)时,控制就返回到前一个已经满足的子目标(如果存在的话),并撤销其有关变量的约束值,然后再使其重新满足.成功后,再继续满足原来的子目标.如果失败的子目标前再无子目标,则控制就返回到该子目标的上一级目标(即该子目标谓词所在规则的头部)使它重新匹配.回溯也是 Prolog 的一个重要机制.
不懂没关系,下面有例子,看完这个 Prolog 程序的运行过程就懂了.
有了上面的基本概念,下面就介绍所 Prolog 程序的运行过程.我们仍以上面给出的 Prolog 程序“程序0”为例.
设所给的询问是:
?-friend(john, Y). (john和谁是朋友?)
则求解目标为:
friend(john, Y).
这时,系统对程序进行扫描,寻找能与目标谓词匹配合一的事实或规则头部.显然,程序中前面的 4 个事实均不能与目标匹配,而第 5 个语句的左端即规则为:
friend(john, Y) :- likes(X, reading), likes(X, music).
的头部可与目标谓词匹配合一.但由于这个语句又是一个规则,所以其结论要成立则必须其前提全部成立.于是,对原目标的求解就转化为对新目标:
likes(X, reading), likes(X, music).
的求解.这实际是经过归结,规则头部被消去,而目标子句变为:
?- likes(X, reading), likes(X, music).
现在依次对子目标:
likes(X, reading)和 likes(X, music)
求解.
子目标的求解过程与主目标完全一样,也是从头对程序进行扫描,不断进行测试和匹配合一等,直到匹配成功或扫描完整个程序为止.
可以看出,对第一个子目标 like(X, reading)的求解因无可匹配的事实和规则而立即失败,进而导致规则:
friend(john, X) :- likes(X, reading), likes(X, music).
的整体失败.于是,刚才的子目标:
likes(X, reading)和 likes(X, music)
被撤销,系统又回溯到原目标 friend(john, X).这时,系统从该目标刚才的匹配语句处(即第 5 句)向下继续扫描程序中的子句,试图重新使原目标匹配,结果发现第 6 条语句的左部,即规则
friend(john, X) :- likes(X, sports), likes(X, music).
的头部可与目标谓词匹配.但由于这个语句又是一个规则,于是,这时对原目标的求解就又转化为依次对子目标:
likes(X, sports)和 likes(X, music)
的求解.这次子目标 likes(X, sports)与程序中的事实立即匹配成功,且变量 X 被约束为 bell.于是,系统便接着求解第 2 个子目标.由于变量 X 已被约束,所以这时第 2 个子目标实际上已变成
likes(bell, music).
由于程序中不存在事实 likes(bell, music),所以该目标的求解失败.于是,系统就放弃这个子目标,并使变量 X 恢复为自由变量,然后回溯到第一个子目标,重新对它进行求解.由于系统已经记住了刚才已同第一子目标谓词匹配过的事实的位置,所以重新求解时,便从下一个事实开始测试.易见,当测试到程序中的第 3 个事实时,第一个子目标便求解成功,且变量 X 被约束为 mary .这样,第 2 个子目标也就变成:
likes(mary, music).
再对它进行求解.这次很快成功.
由于两个子目标都求解成功,所以,原目标 friend(john, Y)也成功,且变量 Y 被约束为 mary(由 Y 与 X 的合一关系).于是,系统回答:
Y = mary
程序运行结束.上述程序的执行过程如图下所示. 图b
上述程序的运行是一个通过推理实现的求值过程.
从上述程序的运行过程来看, Prolog 程序的执行过程是一个(归结)演绎推理过程.其推理方式为反向推理,控制策略是深度优先且有回溯机制,具体实现方法是:自上而下匹配子句;从左向右选择子目标;(归结后)产生的新子目标总是插入被消去的目标处(即目标队列的左部).Prolog 的这种归结演绎方法被称为 SLD(Linear resolution with Selection function for Definite clause)归结, 或 SLD 反驳 - 消解法.这样,SLD 归结就是 Prolog 程序的运行机理,也就是所谓的 Prolog 语言的过程性语义.
评论
查看更多