逻辑型程序设计语言PROLOG详细教程_第1页
逻辑型程序设计语言PROLOG详细教程_第2页
逻辑型程序设计语言PROLOG详细教程_第3页
逻辑型程序设计语言PROLOG详细教程_第4页
逻辑型程序设计语言PROLOG详细教程_第5页
已阅读5页,还剩18页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、逻辑型程序设计语言PROLOG教程2.3. 1逻辑型程序设计语言PROLOG PROLOG的语句 PROLOG语言只有三种语句,分别称为事实、规则和问题。   1.事实(fact) 格式: <谓词名>(<项表>). 功能 一般表示对象的性质或关系。 其中谓词名是以小写英文字母打头的字母、数字、下划线等组成的字符串,项表是以逗号隔开的项序列。 例如: student(john). like( mary ,music). 表示“约翰是学生”和“玛丽喜欢音乐”。2. 规则(rule) 格式: <谓词名>(<项表>):-<谓词名>(

2、<项表>),<谓词名>(<项表>). 功能: 一般表示对象间的因果关系、蕴含关系或对应关系。 其中“:-”号表示“if”(也可以直接写为if),其左部的谓词是规则的结论(亦称为头),右部的谓词是规则的前提(亦称为体),表示零次或多次重复,逗号表示and(逻辑与),即规则的形式是一个逻辑蕴含式。 例如: bird(X):-animal(X),has(X,feather). grandfather(X,Y):-father(X,Z),father(Z,Y). 第一条规则表示“如果X是动物,并且X有羽毛,则X是鸟”;第二条规则就表示“X是Y的祖父,如果存在Z,X是

3、Z的父亲并且Z又是Y的父亲”。 3.问题(question) 格式: ?-<谓词名>(<项表>),<谓词名>(<项表>). 功能 表示用户的询问,它就是程序运行的目标。 例如: ?-student(john). ?-like(mary,X).2.3. 2 PROLOG程序 PROLOG程序一般由一组事实、规则和问题组成。问题是程序执行的起点,称为程序的目标。 例如下面就是一个PROLOG程序。 likes(bell,sports). likes(mary,music). likes(mary,sports). likes(jane ,smith)

4、. friend(john,X):-likes(X,reading),likes(X,music). friend(john,X):-likes(X,sports),likes(X,music). ?-friend(john,Y).可以看出,这个程序中有四条事实、两条规则和一个问题。其中事实、规则和问题都分行书写。规则和事实可连续排列在一起,其顺序可随意安排,但同一谓词名的事实或规则必须集中排列在一起。问题不能与规则及事实排在一起,它作为程序的目标要么单独列出,要么在程序运行时临时给出。 这个程序的事实描述了一些对象(包括人和事物)间的关系;而规则则描述了john交朋友的条件,即如果一个人喜欢

5、读书并且喜欢音乐(或者喜欢运动和喜欢音乐),则这个人就是john的朋友(当然,这个规则也可看作是john朋友的定义);程序中的问题是“约翰的朋友是谁?” 当然,PROLOG程序中的目标可以变化,也可以含有多个语句(上例中只有一个)。如果有多个语句,则这些语句称为子目标。例如对上面的程序,其问题也可以是?-likes(mary,X). 或 ?-likes(mary,music). 或 ?-friend(X,Y). 或 ?-likes(bell,sports), likes(mary,music), friend(john,X). 等等。当然,对于不同的问题,程序运行的结果一般是不一样的。2.3.

6、3 PROLOG程序的运行机理 PROLOG程序的运行是从目标出发,并不断进行匹配、合一、归结,有时还要回溯,直到目标被完全满足或不能满足时为止。1. 自由变量与约束变量 PROLOG中称无值的变量为自由变量,有值的变量为约束变量。一个变量取了某值就说该变量约束于某值,或者说该变量被某值所约束,或者说该变量被某值实例化了。 2. 匹配合一 两个谓词可匹配合一,是指两个谓词的名相同,参量项的个数相同,参量类型对应相同,并且对应参量项还满足下列条件之一: (1)如果两个都是常量,则必须完全相同。 (2)如果两个都是约束变量,则两个约束值必须相同。 (3)如果其中一个是常量,一个是约束变量,则约束值

7、与常量必须相同。 (4)至少有一个是自由变量。例如:下面的两个谓词 pre1("ob1","ob2",Z) pre1("ob1",X,Y) 只有当变量X被约束为"ob2",且Y、Z的约束值相同或者至少有一个是自由变量时,它们才是匹配合一的。 3. 回溯 所谓回溯,就是在程序运行期间,当某一个子目标不能满足(即谓词匹配失败)时,控制就返回到前一个已经满足的子目标(如果存在的话),并撤消其有关变量的约束值,然后再使其重新满足。成功后,再继续满足原子目标。如果失败的子目标前再无子目标,则控制就返回到该子目标的上一级目标(

8、即该子目标谓词所在规则的头部)使它重新匹配。回溯也是PROLOG的一个重要机制。下面,我们介绍PROLOG程序的运行过程。我们仍以上面的程序为例。设所给的询问是 ?-friend(john,Y).(john和谁是朋友?) 则求解目标为 friend(john,Y). 这时,系统对程序进行扫描,寻找能与目标谓词匹配合一的事实或规则头部。显然,程序中前面的四条事实均不能与目标匹配,而第五个语句的左端即规则 friend(john,X):-likes(X,reading),likes(X,music).的头部可与目标谓词匹配合一。但由于这个语句又是一个规则,所以其结论要成立则必须其前提全部成立。于是

9、,对原目标的求解就转化为对新目标 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,readi

10、ng),likes(X,music). 的整体失败。于是,刚才的子目标 likes(X,reading)和likes(X,music) 被撤消,系统又回溯到原目标friend(john,X)。这时,系统从该目标刚才的匹配语句处(即第五句)向下继续扫描程序中的子句,试图重新使原目标匹配,结果发现第六条语句的左部,即规则 friend(john,X):-likes(X,sports),likes(X,music). 的头部可与目标为谓词匹配。但由于这个语句又是一个规则,于是,这时对原目标的求解,就又转化为依次对子目标 likes(X,sports)和likes(X,music) 的求解。这次子目标

11、likes(X,sports)与程序中的事实立即匹配成功,且变量X被约束为bell。于是,系统便接着求解第二个子目标。由于变量X已被约束,所以这时第二个子目标实际上已变成了 likes(bell,music). 由于程序中不存在事实likes(bell,music),所以该目标的求解失败。于是,系统就放弃这个子目标,并使变量X恢复为自由变量,然后回溯到第一个子目标,重新对它进行求解。由于系统已经记住了刚才已同第一子目标谓词匹配过的事实的位置,所以重新求解时,便从下一个事实开始测试。 易见,当测试到程序中第三个事实时,第一个子目标便求解成功,且变量X被约束为mary。这样,第二个子目标也就变成了

12、 likes(mary,music). 再对它进行求解。这次很快成功。 由于两个子目标都求解成功,所以,原目标friend(john,Y)也成功,且变量Y被约束为mary(由Y与X的合一关系)。于是,系统回答: Y=mary 程序运行结束。 上面只给出了问题的一个解。如果需要和可能的话,系统还可把john的所有朋友都找出来。我们把上述程序的运行过程再用示意图(图21)描述如下:图21 PROLOG程序运行机理示例上述程序的运行是一个通过推理实现的求值过程。我们也可以使它变为证明过程。例如,把上述程序中的询问改为 friend(john,mary) 则系统会回答:yes 若将询问改为: rien

13、d(john,smith) 则系统会回答:no 从上述程序的运行过程可以看出,PROLOG程序的执行过程是一个(归结)演绎推理过程。其特点是:推理方式为反向推理,控制策略是深度优先,且有回溯机制。其具体实现方法是:匹配子句的顺序是自上而下;子目标选择顺序是从左向右;(归结后)产生的新子目标总是插入被消去的目标处(即目标队列的左部)。PROLOG的这种归结演绎方法被称为SLD(LinearresolutionwithSelectionfunctionforDefiniteclause)归结,或SLD反驳-消解法。SLD归结就是PROLOG程序的运行机理,它也就是所谓的PROLOG语言的过程性语义

14、。2.4 Turbo PROLOG程序设计 Turbo PROLOG的程序结构 一个完整的Turbo PROLOG(2.0版)程序一般包括常量段、领域段、数据库段、谓词段、目标段和子句段等六个部分。各段以其相应的关键字constants、domains、database、predicates、goal和clauses开头加以标识。: 另外,在程序的首部还可以设置指示编译程序执行特定任务的编译指令;在程序的任何位置都可设置注解。总之,一个完整的TurboPROLOG(2.0版)程序的结构如下 /*<注释>*/ <编译指令> constants <常量说明> d

15、omains <域说明> database <数据库说明> predicates <谓词说明> goal <目标语句> clauses <子句集>当然,一个程序不一定要包括上述所有段,但一个程序至少要有一个predicates段、clauses段和goal段。在大多数情形中,还需要一个domains段,以说明表、复合结构及用户自定义的域名。如若省略goal段,则可在程序运行时临时给出,但这仅当在开发环境中运行程序时方可给出。若要生成一个独立的可执行文件,则在程序中必须包含goal段。另一方面,一个程序也只能有一个goal段。例2.3

16、如果把上节中的程序要作为TurboPROLOG程序,则应改写为: /*例子程序-1*/ DOMAINS name=symbol PREDICATES likes(name,name). friend(name,name) GOAL friend(john,Y),write(Y=,Y). CLAUSESlikes(bell,sports).likes(mary,music).likes(mary,sports).likes(jane,smith).friend(john,X):-likes(X,sports),likes(X,music).friend(john,X):-likes(X,read

17、ing),likes(X,music). 结合上例,我们再对上述程序结构中的几个主要段的内容和作用加以说明(其余段在后面用到时再作说明): 领域段该段说明程序谓词中所有参量项所属的领域。领域的说明可能会出现多层说明,直到最终说明到Turbo PROLOG的标准领域为止(如上例所示)。Turbo PROLOG的标准领域即标准数据类型,包括整数、实数、符号、串和符号等,其具体说明如表2.1所示。表2.1 Turbo PROLOG的标准领域谓词段:该段说明程序中用到的谓词的名和参量项的名(但Turbo PROLOG的内部谓词无须说明)。 子句段:该段是Turbo PROLOG程序的核心,程序中的所有

18、事实和规则就放在这里,系统在试图满足程序的目标时就对它们进行操作。目标段:该段是放置程序目标的地方。目标段可以只有一个目标谓词,例如上面的例子中就只有一个目标谓词;也可以含有多个目标谓词,如: goal readint(X),Y=X+3,write("Y=",Y). 就有三个目标谓词。这种目标称为复合目标。 另外,一般称程序目标段中的目标为内部目标,而称在程序运行时临时给出的目标为外部目标。 Turbo PROLOG的数据与表达式1.领域1)标准领域 Turbo PROLOG中不定义变量的类型,只说明谓词中各个项的取值域。2)结构 结构也称复合对象,它是TurboPROLO

19、G谓词中的一种特殊的参量项(类似于谓词逻辑中的函数)。 结构的一般形式为 <函子>(<参量表>) 其中函子及参量的标识符与谓词相同。注意,这意味着结构中还可包含结构。所以,复合对象可表达树形数据结构。例如下面的谓词 likes(Tom,sports(football,basketball,table-tennis). 中的 sports(football,basketball,table-tennis) 就是一个结构,即复合对象。 又如: person("张华",student("西安石油学院"),address("中国

20、","陕西","西安").  reading("王宏",book("人工智能技术基础教程","西安电子科技大学出版社").  friend(father("Li"),father("Zhao"). 这几个谓词中都有复合对象。 复合对象在程序中的说明,需分层进行。例如,对于上面的谓词 likes(Tom,sports(football,basketball,table-tennis). 在程序中可说明如下: domains na

21、me=symbol sy=symbol sp=sports(sy,sy,sy) predicates likes(name,sp)3) 表 表的一般形式是 x1,x2,xn 其中xi(i=1,2,n)为PROLOG的项,一般要求同一个表的元素必须属于同一领域。 不含任何元素的表称为空表,记为。例如下面就是一些合法的表。 1,2,3apple,orange,banana,grape,cane"PROLOG","MAENS","PROGRAMMING","in logic"a,b,c,d,e表的最大特点是其元素个数可在

22、程序运行期间动态变化。表的元素也可以是结构或表,且这时其元素可以属于不同领域。 例如:name("Li Ming"),age(20),sex(male),address(xi an)1,2,3,4,5,6,7都是合法的表。后一个例子说明,表也可以嵌套。实际上,表是一种特殊的结构。它是递归结构的另一种表达形式。这个结构的函数名取决于具体的PROLOG版本。这里我们就用一个圆点来表示。 下面就是一些这样的结构及它们的表表示形式:结构形式 表形式·(a,) a·(a,·(b,) a,b·(a,·(b,·(c,) a,b,

23、c 表的说明方法是在其组成元素的说明符后加一个星号*。如: domains lists=string* predicates pl(lists) 就说明谓词pl中的项lists是一个由串string组成的表。 对于由结构组成的表,至少得分三步说明。例如对于下面谓词p中的表 p(name("Liming"),age(20) 则需这样说明: domains rec=seg* seg=name(string);age(integer) predicates p(rec)2. 常量与变量由上面的领域可知,Turbo PROLOG的常量有整数、实数、字符、串、符号、结构、表和文件这八

24、种数据类型。同理,Turbo PROLOG的变量也就有这八种取值。另外,变量名要求必须是以大写字母或下划线开头的字母、数字和下划线序列,或者只有一个下划线。这后一种变量称为无名变量。3. 算术表达式 Turbo PROLOG提供了五种最基本的算术运算:加、减、乘、除和取模,相应运算符号为+、-、*、/、mod。这五种运算的顺序为:*、/、mod优先于+、-。同级从左到右按顺序运算,括号优先。算术表达式的形式与数学中的形式基本一样。例如: 数学中的算术表达式 PROLOG中的算术表达式 x+yz X+Y*Z ab-c/d A*B-C/D u mod v U mod V(表示求U除以V所得的余数)

25、即是说,Turbo PROLOG中算术表达式采用通常数学中使用的中缀形式。这种算术表达式为PROLOG的一种异体结构,若以PROLOG的结构形式来表示,则它们应为 +(X,*(Y,Z) -(*(A,B),/(C,D) mod(U,V) 所以,运算符+、-、*、/和mod实际也就是PROLOG内部定义好了的函数符。 在Turbo PROLOG程序中,如果一个算术表达式中的变元全部被实例化(即被约束)的话,则这个算术表达式的值就会被求出。求出的值可用来实例化某变量,也可用来同其他数量进行比较,用一个算术表达式的值实例化一个变量的方法是用谓词“is”或“=”来实现。例如: Y is X+5 或 Y=

26、X+5 (*) 就使变量Y实例化为X+5的值(当然X也必须经已被某值实例化),可以看出,这里对变量Y的实例化方法类似于其他高级程序语言中的“赋值”,但又不同于赋值。例如,在PROLOG中下面的式子是错误的: X=X+14. 关系表达式 Turbo PROLOG提供了六种常用的关系运算,即小于、小于或等于、等于、大于、大于或等于和不等于,其运算符依次为 <,<=,=,>,>=,<> Turbo PROLOG的关系表达式的形式和数学中的也基本一样,例如: 数学中的关系式 Turbo PROLOG中的关系式 X+1Y X+1>=Y XY X<>Y

27、即是说,Turbo PROLOG中的关系式也用中缀形式。当然,这种关系式为Turbo PROLOG中的异体原子。若按Turbo PROLOG中的原子形式来表示,则上面的两个例子为 >=(X+1,Y)和<>(X,Y) 所以上述六种关系运算符,实际上也就是Turbo PROLOG内部定义好了的六个谓词。这六个关系运算符可用来比较两个算术表达式的大小。 例如: brother(Name1,Name2):-person(Name1,man,Age1), person(Name2,man,Age2), mother(Z,Name1),mother(Z,Name2), Age1>A

28、ge2. 需要说明的是,“=”的用法比较特殊,它既可以表示比较,也可以表示约束值,即使在同一个规则中的同一个“=”也是如此。 例如:(例一) p(X,Y,Z):-Z=X+Y. 当变量X、Y、Z全部被实例化时,“=”就是比较符。如:对于问题 Goal:p(3,5,8). 机器回答:yes。而对于 Goal:p(3,5,7). 机器回答:no。 即这时机器把X+Y的值,与Z的值进行比较。 (例二)但当X,Y被实例化,为Z未被实例化时,“=”号就是约束符。如: Goal:p(3,5,Z).机器回答:Z=8这时,机器使Z实例化为X+Y的结果。 输入与输出 虽然PROLOG能自动输出目标子句中的变量的值

29、,但这种输出功能必定有限,往往不能满足实际需要;另一方面,对通常大多数的程序来说,运行时从键盘上输入有关数据或信息也是必不可少的。为此每种具体PROLOG一般都提供专门的输入和输出谓词,供用户直接调用。例如,下面就是TorboPROLOG的几种输入输出谓词: (1) readln (X)。这个谓词的功能是从键盘上读取一个字符串,然后约束给变量X。 (2) readint (X)。 这个谓词的功能是从键盘上读取一个整数,然后约束给变量X,如果键盘上打入的不是整数则该谓词失败。 (3) readreal (X)。 这个谓词的功能是从键盘上读取一个实数,然后约束给变量X,如果键盘上打入的不是实数则该

30、谓词失败。 (4) readchar(X)。 这个谓词的功能是从键盘上读取一个字符,然后约束给变量X,如果键盘上打入的不是单个字符,则该谓词失败。 (5) write(X1,X2,Xn)。 这个谓词的功能是把项Xi(i=1,2,n)的值显示在屏幕上或者打印在纸上,当有某个Xi未实例化时,该谓词失败,其中的Xi可以是变量,也可以是字符串或数字。 (6) nl换行谓词。它使后面的输出(如果有的话)另起一行。另外,利用write的输出项"n"也同样可起换行作用。例如: write("name"), n l ,write("age")与wri

31、te("name","n","age")的效果完全一样。例2.4用上面的输入输出谓词编写一个简单的学生成绩数据库查询程序。PREDICATESstudent(integer,string,real)gradeGOALgrade.CLAUSESstudent(1,"张三",90.2).student(2,"李四",95.5).student(3,"王五",96.4).grade:-write("请输入姓名:"),readln(Name),student(-,

32、Name,Score),nl,write(Name,"的成绩是",Score).grade:-write(“对不起,找不到这个学生!”). grade:-write("对不起,找不到这个学生!").下面是程序运行时的屏幕显示:请输入姓名: 王五 王五的成绩是96.4。 分支与循环PROLOG中并无专门的分支和循环语句,但PROLOG也可实现分支和循环程序结构。1.分支对于通常的IF-THEN-ELSE分支结构,PROLOG可用两条同头的并列规则实现。例如,将 IF x>0THENx:=1 ELSE x:=0用PROLOG实现则是Br :-x>

33、0,x=1.Br :-x=0.类似地,对于多分支,可以用多条规则实现。例如:Br :-x>0,x=1.Br :-x=0,x=0.Br :-x<0,x=-1.2.循环PROLOG可以实现计循环次数的FOR循环,也可以实现不计循环次数的DO循环。例如下面的程序段就实现了循环,它使得write语句重复执行了三次,而打印输出了三个学生的记录。 student(1,"张三",90.2). student(2,"李四",95.5). student(3,"王五",96.4). print:-student(Number,Name,Sc

34、ore), write(Number,Name,Score),n l , Number=3.这个例子可以看作是计数循环。当然,也可以通过设置计数器而实现真正的计数循环。下面的程序段实现的则是不计数的DO循环。 student(1,"张三",90.2). student(2,"李四",95.5). student(3,"王五",96.4). print:-student(Number,Name,Score), write(Number,Name,Score),nl, fail. print:-. 这个程序段中的fail是一个内部谓词,它

35、的语义是恒失败。这个程序段与上面的程序段的差别仅在于把原来用计数器(或标记数)循环控制语句变成了恒失败谓词fail,另外再增加了一个print语句。增加这个语句的目的是为程序设置一个出口。因为fail是恒失败,下面若无出口的话,将引起print本身的失败。进而又会导致程序中的连锁失败。 动态数据库动态数据库就是在内存中实现的动态数据结构。它由事实组成,程序可以对它操作,所以在程序运行期间它可以动态变化。Turbo PROLOG提供了三个动态数据库操作谓词:asserta (<fact>).assertz (<fact>).retract (<fact>).

36、其中fact表示事实。这三个谓词的功能是: asserta (<fact>).把fact插入当前动态数据库中的同名谓词的事实之前; assertz (<fact>).把fact插入当前动态数据库中的同名谓词的事实之后; retract(<fact>).把fact从当前动态数据库中删除。 例如语句 asserta(student(20,"李明",90.5). 将在内存的谓词名为student的事实前插入一个新事实: student(20,"李明",90.5) 如果内存中还没有这样的事实,则它就是第一个。又如语句 retr

37、act(student(20,-,-). 将从内存的动态数据库中的删除事实 student(20,-,-)它可解释为学号为20的一个学生的记录。注意,这里用了无名变量-。可以看出,PROLOG提供的动态数据库机制,可非常方便地实现堆栈、队列等动态数据结构,提供的数据库操作谓词大大简化了编程。另外,PROLOG还提供了谓词 save(<filename>). consult(<filename>).前者可将当前的动态数据库存入磁盘文件,后者则可将磁盘上的一个事实数据文件调入内存。 表处理与递归 表是PROLOG中一种非常有用的数据结构。表的表述能力很强,数字中的序列、集合

38、,通常语言中的数组、记录等均可用表来表示。表的最大特点是其长度不固定,在程序的运行过程中可动态地变化。具体来讲,就是在程序运行时,可对表施行一些操作,如给表中添加一个元素,或从中删除一个元素,或者将两个表合并为一个表等等。用表还可以方便地构造堆栈、队列、链表、树等动态数据结构。 表还有一个重要特点,就是它可分为头和尾两部分。表头是表中第一个元素,而表尾是表中除第一个元素外的其余元素按原来顺序组成的表。例如下面的例子: 表 表头 表尾 1,2,3,4,5 1 2,3,4,5 apple,orange,banana apple orange,bananaa,b,c,d,e a,b c,d,e &q

39、uot;PROLOG" "PROLOG“ 无定义 无定义在程序中是用竖线“|”来区分表头和表尾的,而且还可以使用变量。例如一般地用H|T来表示一个表,其中H、T都是变量,H为表头,T为表尾。注意,此处H是一个元素(表中第一个元素),而T则是一个表(除第一个元素外的表中其余元素按原来顺序组成的表)。表的这种表示法很有用,它为表的操作提供了极大的方便。下面我们就给出用这种表示法通过匹配合一提取表头和表尾的例子。 表1 表2 合一后的变量值X|Y a,b,c X=a,Y=b,cX|Y a X=a,Y=a|Y X,b X=a,Y=bX,Y,Z a,b,c X=a,Y=b,Z=ca,

40、Y|Z X,b,c X=a,Y=b,Z=c还需说明的是,表中的竖杠“|”后面只能有一个变量。例如写法X|Y,Z就是错误的。但竖杠的前面的变量可以多于一个。例如写法X,Y|Z是允许的。这样,这个表同a,b,c匹配合一后,有 X=a,Y=b,Z=c另外,竖杠的前面和后面也可以是常量,例如a|Y和X|b都是允许的,但注意,后一个表称为无尾表,如果它同表a|Y匹配,则有 X=a,Y=b (而不是Y=b) 如果无竖杠“|”,则不能分离出表尾。例如,表X,Y,Z与a,b,c合一后得X=a,Y=b,Z=c。其中变量Z并非等于c。例2.5 设计一个能判断对象X是表L的成员的程序。 我们可以这样设想: (1)如

41、果X与表L中的第一个元素(即表头)是同一个对象,则X就是L的成员; (2)如果X是L的尾部的成员,则X也就是L的成员。 根据这种逻辑关系,于是有下面的PROLOG程序: member(X,X|Tail). member(X,Head|Tail):-member(X,Tail). 其中第一个子句的语义就是上面的第一句话,第二个子句的语义就是上面的第二句话。可以看出,这个程序中使用了递归技术,因为谓词member的定义中又含有它自身。利用这个程序我们就可以判定任意给定的一个对象和一个表之间是否具有member(成员)关系。 例如,我们取表L为a,b,c,d,取X为a,对上面的程序提出如下询问: G

42、oal:member(a,a,b,c,d). 则有回答:yes 同样对于询问: Goal:member(b,a,b,c,d). Goal:member(c,a,b,c,d). Goal:member(d,a,b,c,d). 都有回答:yes但若询问 Goal:member(e,a,b,c,d). 则回答:no 如果我们这样询问 Goal:member(X,a,b,c,d). 意思是要证明存在这样的X,它是该表的成员,这时系统返回X的值,即 X=a 如果需要的话,系统还会给出X的其他所有值。 例2.6 表的拼接程序,即把两个表连接成一个表。  append(,L,L).append(H

43、|T,L2,H|Tn):-append(T,L2,Tn).程序中第一个子句的意思是空表同任一表L拼接的结果仍为表L;第二个子句的意思是说,一个非空的表L1与另一个表L2拼接的结果L3是这样一个表,它的头是L1的头,它的尾是由L1的尾T同L2拼接的结果Tn。这个程序刻划了两个表与它们的拼接表之间的逻辑关系。可以看出,谓词append是递归定义的,子句append(,L,L).为终结条件,即递归出口。 对于这个程序,如果我们询问 Goal:append(1,2,3,4,5,L). 则系统便三次递归调用程序中的第二个子句,最后从第一个子句终止,然后反向依次求出每次的拼接表,最后输出 L=1,2,3,

44、4,5当然,对于这个程序也可以给出其他各种询问,如:Goal:append(1,2,3,4,5,1,2,3,4,5).系统回答:yesGoal:append(1,2,3,4,5,1,2,3,4,5,6).系统回答:noGoal:append(1,2,3,Y,1,2,3,4,5).系统回答:Y=4,5Goal:append(X,4,5,1,2,3,4,5). 系统回答:X=1,2,3Goal:append(X,Y,1,2,3,4,5).系统回答:X=,Y=1,2,3,4,5X=1,Y=2,3,4,5X=1,2,Y=3,4,5X=1,2,3,Y=4,5等等(如果需要所有解的话)。 例2.7 表的输

45、出。 print(). print(H|T):-write(H),print(T).例2.8 表的倒置,即求一个表的逆序表。 reverse(,). reverse(H|T,L):-reverse(T,L1),append(L1,H,L). 这里,reverse的第一个项是输入,即原表,第二个项是输出,即原表的倒置。 回溯控制PROLOG在搜索目标解的过程中,具有回溯机制,即当某一个子目标Gi不能满足时,就返回到该子目标的前一个子目标Gi-1,并放弃Gi-1的当前约束值,使它重新匹配合一。在实际问题中,有时却不需要回溯,为此PROLOG中就专门定义了一个阻止回溯的内部谓词“!”,称为截断谓词。

46、截断谓词的语法格式很简单,就是一个感叹号“!”。!的语义是: (1)若将“!”插在子句体内作为一个子目标,它总是立即成功; (2)若“!”位于子句体的最后,则它就阻止对它所在子句的头谓词的所有子句的回溯访问,而让回溯跳过该头谓词(子目标),去访问前一个子目标(如果有的话); (3)若“!”位于其他位置,则当其后发生回溯且回溯到“!”处时,就在此处失败,并且“!”还使它所在子句的头谓词(子目标)整个失败(即阻止再去访问头谓词的其余子句(如果有的话),即迫使系统直接回溯到该头谓词(子目标)的前一个子目标(如果有的话))。 例2.9考虑下面的程序: p(a). (21) p(b). (22) q(b

47、). (23) r(X):-p(X),q(X). (24) r(c). 对于目标:r(Y). 可有一个解 Y=b 但当我们把式(24)改为 r(X):-p(X),!,q(X). (24) 时,却无解。 这是由于添加了截断谓词“!”。因为式(24)中求解子目标p(X)时,X被约束到a,然后跳过“!”,但在求解子目标q(a)时遇到麻烦,于是又回溯到“!”,而“!”阻止了对p(X)的下一个子句p(b)和r的下一个定义子句r(c)的访问。从而,导致整个求解失败。例2.10 设有程序:g0:-g11,g12,g13. (25)g0:-g14. (26)g12:-g21,!,g23. (27)g12:-g

48、24,g25. (28).给出目标:g0.假设运行到子目标g23时失败,这时如果子句(27)中无!的话,则会回溯到g21,并且,如果g21也失败的话,则会访问下面的子句(28)。但由于有!存在,所以不能回溯到g21,而直接宣告g12失败。于是,由子句(25),这时则回溯到g11。如果我们把子句(27)改为 g12: -g21, g23,!. (29)当然这时若g23失败时,便可回溯到g21,而当g21也失败时,便回溯到g12,即子句(28)被“激活”。但对于修改后的程序,如果g13失败,则虽然可回溯到g12,但对g12不做任何事情,便立即跳过它,而回溯到g11,如果子句(29)中无!,则当g1

49、3失败时,回溯到g12便去考虑子句(28),只有当子句(28)再失败时才回溯到g11。 程序举例下面我们给出几个简单而又典型的例子程序。通过这些程序,读者可以进一步体会和理解PROLOG程序的风格和能力,也可以掌握一些基本的编程技巧。例2.11 下面是一个简单的路径查询程序。程序中的事实描述了如图22所示的有向图,规则是图中两节点间有通路的定义。图22 有向图predicates road(symbol,symbol) path(symbol,symbol)clauses road(a,b). road(a,c). road(b,d). road(c,d). road(d,e). road(b,e). path(X,Y):-road(X,Y). path(X,Y):-road(X

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论