第一章:Getting start
1、hello
world:
write(“Hello
World”),nl,write(“Welcome to Prolog”),nl.
以.号做结束,有一系列目标(goal)组成(一般也称为查询query),目标之间用,号隔开,这里的write和nl其实是内建的IO谓词,总共4个目标按顺序执行,nl是开始一个新行,所有目标达成,Prolog系统会输出yes。
2、halt也是BIPs,用于结束Prolog系统,statistics用于系统统计(cpu、内存等)。BIPs都是会产生副作用的谓词。比如write就是会产生输出到用户屏幕副作用的IO谓词。
3、第一个程序,写入下列代码并保存为prog1.pl:
dog(fido).
cat(felix).
animal:-dog(X).
通过consult谓词,将该程序导入数据库(本质上,Prolog系统就是一个全局数据库),
分析下代码:
dog(fido).
cat(felix).
就是所谓事实(fact),dog和cat就是谓词,而fido和felix是atom,这里陈述了两个事实:fido是一只狗,felix是一只猫。animal:-dog(X).
这句就是规则(rule),:-符号可以理解为如果(注:if),X是变量,这里描述的规则就是:如果X是狗,那么X就是动物。因此,依据事实和规则,Prolog的推理系统可以推论:fido是狗,所以fido是动物:
| ?- animal(fido).
yes
显然,根据animal规则,felix不是动物,虽然它是:
| ?- animal(felix).
no
4、Prolog的注释
/* this is a comment */
5、查询,dog(X),查询所有满足谓词dog的X,也就是找出所有的狗狗。
dog(X),cat(X).查询所有是狗又是猫的“东西”。Listing(dog),列出所有定义了谓词dog的语句。
6、Prolog的数据类型:
1)数字,Number,623,+3,-.245
2)Atom,所有的不包括数值在内的常量,这与Erlang中的atom概念是一脉相承
包括:以小写字母开头的字母、数字、下划线的组合,单引号括起来的字符序列,+-*/<>=@特殊字符组成的序列
3)变量:在查询中代表未决的term,以大写字母或者下划线开头,跟Erlang一样,_表示哑元
4)组合Term,类似其他语言中的记录结构,以一个atom开头,后接一个参数列表,参数也都是term,参数的个数就是它的arity(Erlang也是如此),例如:
read(X)
dog(henry)
likes(dog(henry),Y)等
5)列表,如:
[dog,cat,mypred,[a,b,c],hello]
6)其他类型,某些
Prolog方言可能会有字符串类型,用于处理字符串。
第二章 语句和谓词
-
一个Prolog程序就是由一系列语句(clause)组成的,语句可以多行,以引文句号结束。两种基础语句:事实和规则。
-
事实语句,是由atom或者组合term构成(两者统称为call
terms),如:
chrismas.
likes(john,mary).
-
规则,形式如下:
head:-t1,t2,…,tk.
(k>=1)
head成为规则的头部,也必须是call
term,:-称为颈部操作符,读作if,而t1,t2…tk就是语句的body,它们描述了头部的结论所需要满足的条件。Body是由一个或者多个componet组成,compont就是目标,以逗号隔开,逗号表示and的关系。从另一个角度看,head可以成为目标,body是它的子目标,规则就是为了达到目标head,必须先达到子目标t1,t2…tk。
例子:
large_animal(X):-animal(X),large(X).
go:-write(‘hello
world’),nl.
-
谓词,所有语句的头部都包括了一个谓词定义,不同参数的同名谓词是不同的谓词,参数数目就是所谓元数(arity)。谓词可以记录为pred/n,比如parent/1,表示谓词名为parent,而参数个数是一个,这个与Erlang相同。谓词可分为用户自定义的维持和built-in谓词(BIPs)。IO谓词如write,nl就是BIPs,它们都是总会成功的谓词,并带来相应的IO副作用(输出和换行)。用户不能重定义BIPs。
-
谓词的递归定义,分为直接和间接递归,例子:
likes(john,X):-likes(X,Y),dog(Y). 描述的规则为:john喜欢的是那种至少喜欢一只狗的人。
-
loading语句,包括两个BIPs:consult/1和reconsult/1,用于产生将文件中的语句导入数据库的副作用,两者的区别是,reconsult会覆盖之前定义的相同谓词,而consult不会。consult[‘prog1.pl’]可以简化为[‘prog1.pl’].同样,reconslt[‘prog1.pl’]可以简写为[-‘prog1.pl’]
-
变量,一开始所有的变量都是未绑定的,当目标被执行时,变量可能被绑定或者解绑定。变量存在作用域,不同语句中的同名变量没有任何关系。
-
量词,
1)全称量词,出现在事实或者规则head部分的变量,表示事实或者规则的该变量的所有可能值,这样的变量成为全称量词,如
large_animal(X):-animal(X),large(X). 中的X。
2)存在量词,不在事实或者规则的head部分中存在,但是在body部分中出现的量词,仅仅为了表示该变量至少存在一个值,这样的变量称为存在量词。例如:
person(dennis,zane,male,25,programmer).
man(A):-person(A,B,male,C,D).
man谓词body部分的B,C,D变量就是存在量词
9.匿名变量,就是所谓哑元,下划线_表示,表示你并不care这个变量的值是什么,仅仅为了占位,用以表示任意值,与Erlang中的意义一致。
第三章
1、这一章主要将描述Prolog系统是如何满足目标的执行。
2、Prolog系统是按照顺序执行目标的,每个目标都是由call
term组成,每个目标都与一个相应的谓词相关联,谓词的名称称为functor,而参数个数就是元数(arity)。Prolog系统是从上到下,依据语句的head部分来匹配目标,如果匹配,将输出yes,否则就是no。对于用户定义的目标,Prolog没有找到任何事实或者规则与之匹配的话,那么就是fail。这不是什么未知或者不确定,这个其实就是所谓的封闭世界假设(closed
world
assumption):任何结论如果无法从数据库中的事实和规则中得到证明,那么这个结论就是否定的,没有什么系统不确定或者未知这样的中间位置。
3、Prolog的匹配算法——联合(unification),
变量可以跟任何term联合,其中包括了变量,其实就是变量的绑定。例如:
X=1将X与1联合.
dog(X)与dog(ferris),将X与ferris联合。
看call
terms的联合过程:
1)如果两个call
term都是atom,只有当它们是一样的时候才可以联合,比如:
test跟test联合成功
dennis跟'dennis'联合成功
apple跟fuck联合失败
2)对于组合call
term的联合,要求两个call
term有一样的functor和arity,并且参数也要成对地联合成功。
联合的详细规则如下:
1)两个atom当且仅当它们是一样的时候才是联合成功的。
2)两个组合的term联合成功,当且仅当两者有一样的functor和airty,并且参数也要从左到右两两成对地联合成功。
3)两个number联合成功,当且仅当它们是一样的时候,例如7与7联合成功,而7与6.9就失败
4)两个未绑定的变量总是联合成功的,两者互相绑定
5)一个未绑定变量和一个不是变量的term也总是联合成功的,将变量绑定为该term
6)一个绑定的变量可以被认为它所绑定的值。例如
pred(X,X,man)
与pred(landon,dog,A)联合失败,因为在第一个参数联合成功后,X就被认为是landon,那么在尝试联合第二个参数的时候,显然landon与dog联合失败。
7)两个列表联合成功,当且仅当它们拥有相同数目的元素,并且元素间从左到右成对地联合成功。
8)嵌套结构按照这些规则递归,其他情况下的联合都是失败的。
4、目标的求值,两张图描述:
5、回溯(backtracking),回溯就是一个返回前一个满足的目标,寻找其他方式重新满足该目标的过程。回溯,顾名思义就是退回去,再来过,当输入;号,就强制Prolog系统回溯以寻找更多的匹配
6、目标求值的概览:
第四章 操作符
1、通过op谓词,可以将用户自定义的谓词转成某种操作符,例如:
likes(dennis,catty).
我们更希望表达成:
dennis likes catty.
这在默认情况是不行的,通过op谓词转化likes谓词成中缀操作符:
op(150,xfy,likes).
然后就可以这样使用likes谓词了:
dennis likes catty.
op谓词一般形式
op(操作符优先级,(xfy|xf|fy),谓词名称)
2、算术运算:通过内建的is/2谓词来进行算术运算,is/2是一个内建的中缀运算符,例如:
X is 2.
X is 3,Y is X+3.
出现在第二个参数的变量必须是已经绑定。+
- * /称为算术运算符,还有一类称为算术函数,它们并不是谓词,例如abs/1
sqrt/1等,完整列表:
+ - * /
X//Y 两个整数的商
X^Y 表示X的Y次方,在gnu
prolog上是**,与ruby一样。
-X 一元操作符
abs(X)
sqrt(X)
sin(X)
cos(X)
max(X,Y)
is/2的第一个参数也可以是表达式或者数字,在此情况下,两个参数都会被计算,如果相等,则succeeds,否则失败。因此is/2谓词也可以解释为,求值看两个参数是否可以联合成功。如果第一个参数是变量,就将第二个参数的值绑定在该变量上,如果第一个参数是数值或者算术表达式,就比较两个参数的值是否相等,相等则联合成功,如果第一个参数是atom,term.list等,联合的情况依赖于实现。永远失败的is/2:
X is X+1.总是失败。
操作符的优先级与算术中的一样,可以通过括号强制优先级。
算术比较操作符:=:=,=\=,>,>=,<,=<
3、等价操作符:
1)算术表达式比较:
E1=:=E2
成功当且仅当两个表达式求值的结果一致。
E1=\=E2
成功当且仅当两个表达式求值的结果不一致。
2)Term相同比较:
Term1==Term2成功当且仅当Trem1跟Term2完全相同。
因此:
likes(X,prolog)==likes(X,prolog)相同
likes(Y,prolog)==likes(Y,prolog)失败,X与Y是不同的变量
3+7==6+4
失败,两个表达式不会被求值,显然不同
Term1
\==Term2成功当且仅当Trem1跟Term2不同。
3)Term联合的比较:
=操作符与==类似,不同在于,Term1=Term2当且仅当Term1和Term2联合成功的时候成功,也就是能找到某种方式绑定变量的值,来让两者相同。例如
6+X=6+3。成功,X绑定为3
6+4=3+7 仍然失败
X=0,X=:=0.
成功,将X绑定为0,算术比较成功。
=的相反操作符就是\=
4、逻辑操作符:取反操作符not,表示or的;
例如:
X=0,not X is 0. 返回no
6<3;7 is 2+5.返回yes