今年四月左右,我心血来潮地为本身立了一个学习Prolog的目标——对,就是那门以逻辑编程和人工智能为卖点的语言。不只要学会它的基本用法,还妄想用它像朋友圈广告里的Python那样,用来处理Excel文件中的大数据!php
尽管处理大数据是开个玩笑,但学习Prolog的目标是真的。既然要学习一门编程语言,就必须找一本靠谱的教材。在无中生友以后,我选择了由谭浩强老先生主编的《Learn Prolog Now》做为入门读物。html
尽管《Learn Prolog Now》的内容一点也不real world,却按部就班、很是地适合初学者,每一章的结尾还准备了“上机题”。出人意料的是,仅仅在第三章就遇到了不会作的题目。在焦急地苦战一番未果后,我拖着疲惫的身躯搁置了它,继续学习后面的章节。git
时隔五个月,我再次尝试解答这道题目。却惊喜地发现,只须要冷静地分析再仔细运用前三章学过的知识,解决这道题目也就是水到渠成的事情了。github
讲了这么多,是时候揭晓这它的真面目了。因为第三题以第二题为基础,所以一并搬运了过来算法
感兴趣的朋友也能够直接移步源网页查看。编程
看完上面的题目,只学过主流编程语言的朋友大概会是一头雾水,毕竟不管是代码仍是术语,都与平日里使用的截然不同。我来试着解释一下。像byCar(auckland, hamilton)
和byTrain(metz, frankfurt)
这样的代码,用Prolog的术语来说叫作“事实”。就像数学中的公理同样,它们老是成立的。若是向Prolog提问,它会给出确定的回答编程语言
byCar
和byTrain
被称为“谓词”,auckland
和hamilton
则是“原子”。学习
第二题要求定义travel/2
,第三题要求定义travel/3
。travel
是谓词的名字,2和3则是它所接受的参数的个数。定义一个谓词就是给出描述它什么时候成立的“规则”,举个例子,能够定义一个名为len
的谓词,只有当第二个参数等于第一个参数的长度时才成立大数据
以大写字母开头的标识符(如题目中的X
,上图中的T
、L
)是变量,在归一化(unification)时Prolog可以为它们赋值使得查询成立。人工智能
鉴于本文不是Prolog的入门教程,各位读者若是想进一步了解Prolog,还请移步《Learn Prolog Now》的相关章节。
讲了这么多,该进入正题了。第二题其实不难,细心的读者应该已经发现,这题能够用递归来解决(就像上文的len
同样)。
设谓词travel
的两个参数分别叫作S
和E
,各表明起点和终点。显然,travel(S, E)
成立,当且仅当:
S
搭乘汽车(byCar
)、火车(byTrain
),或飞机(byPlane
)抵达E
,或者;M
,能够从S
搭乘汽车、火车,或飞机抵达M
,而且travel(M, E)
也成立。上述算法能够轻松地写成Prolog代码
byCar(auckland,hamilton). byCar(hamilton,raglan). byCar(valmont,saarbruecken). byCar(valmont,metz). byTrain(metz,frankfurt). byTrain(saarbruecken,frankfurt). byTrain(metz,paris). byTrain(saarbruecken,paris). byPlane(frankfurt,bangkok). byPlane(frankfurt,singapore). byPlane(paris,losAngeles). byPlane(bangkok,auckland). byPlane(singapore,auckland). byPlane(losAngeles,auckland). travel(S, E) :- just_go(S, E). travel(S, E) :- just_go(S, M), travel(M, E). just_go(S, E) :- byCar(S, E). just_go(S, E) :- byTrain(S, E). just_go(S, E) :- byPlane(S, E).
让Prolog告诉我们这个travel/2
写得对不对
精彩!
Prolog不只知道一个查询是否成立,还知道这个查询在什么参数下成立。例如,可让Prolog告诉我们,从valmont
能够抵达哪一些城市,以及哪一些城市能够抵达auckland
这正是在接下来的题目中须要发扬光大的能力。
第三题所要求的travel
是一个接受三个参数的谓词,第三个参数由从起点到终点的途径城市构成。设这个新的变量为R
,那么travel(S, E, R)
成立当且仅当:
S
抵达E
,而且R
为go(S, E)
,或者;M
,以及另外一条路径R2
。能够从S
抵达M
,而且travel(M, E, R2)
成立,而且R
为go(S, M, R2)
。那么如何在规则中描述R
的结构呢?莫非是像上面的谓词len
那样,在:-
的右侧写上形如R is go(S, M, R2)
这样的代码?
并非。
借助Prolog强大的模式匹配能力,只须要在:-
的左边声明R
的结构便可
byCar(auckland,hamilton). byCar(hamilton,raglan). byCar(valmont,saarbruecken). byCar(valmont,metz). byTrain(metz,frankfurt). byTrain(saarbruecken,frankfurt). byTrain(metz,paris). byTrain(saarbruecken,paris). byPlane(frankfurt,bangkok). byPlane(frankfurt,singapore). byPlane(paris,losAngeles). byPlane(bangkok,auckland). byPlane(singapore,auckland). byPlane(losAngeles,auckland). travel(S, E, go(S, E)) :- just_go(S, E). travel(S, E, go(S, M, R)) :- just_go(S, M), travel(M, E, R). just_go(S, E) :- byCar(S, E). just_go(S, E) :- byTrain(S, E). just_go(S, E) :- byPlane(S, E).
加载这段代码后,就能让Prolog告诉咱们,如何从valmont
去往losAngeles
了
Prolog不只找出了题目中所给出的答案(见上图的第二行X =
),还找出了另一条可行的路径。
确实不难,难怪能够做为第三章的习题。