共计 2735 个字符,预计需要花费 7 分钟才能阅读完成。
往年四月左右,我灵机一动地为本人立了一个学习 Prolog 的指标——对,就是那门以逻辑编程和人工智能为卖点的语言。不仅要学会它的根本用法,还妄想用它像朋友圈广告里的 Python 那样,用来解决 Excel 文件中的大数据!
只管解决大数据是开个玩笑,但学习 Prolog 的指标是真的。既然要学习一门编程语言,就必须找一本靠谱的教材。在无中生友之后,我抉择了 由谭浩强老先生主编的《Learn Prolog Now》作为入门读物。
只管《Learn Prolog Now》的内容一点也不 real world,却循序渐进、十分地适宜初学者,每一章的结尾还筹备了“上机题”。出乎意料的是,仅仅在第三章就遇到了不会做的题目。在着急地苦战一番未果后,我拖着疲乏的身躯搁置了它,持续学习前面的章节。
时隔五个月,我再次尝试解答这道题目。却惊喜地发现,只须要沉着地剖析再认真使用前三章学过的常识,解决这道题目也就是瓜熟蒂落的事件了。
所以到底是个什么题?
讲了这么多,是时候揭晓这它的真面目了。因为第三题以第二题为根底,因而一并搬运了过去
感兴趣的敌人也能够间接移步源网页查看。
看完下面的题目,只学过支流编程语言的敌人大略会是一头雾水,毕竟无论是代码还是术语,都与素日里应用的天壤之别。我来试着解释一下。像 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 =
),还找出了另外一条可行的门路。
后记
的确不难,难怪能够作为第三章的习题。
浏览原文