若是你想得到更好的阅读体验,能够前往我在 github 上的博客进行阅读,http://lcomplete.github.io/blog/2013/06/28/sevenlang-prolog/。python
目前商业上普遍使用的编程语言可能是命令式或函数式的编程语言,这些语言在某些方面具备很高的类似度,好比 python 和 ruby 在不少地方是相通的,学会了一门,再学另外一门便可以事半功倍,不少语言都是如此,然而今天要介绍的这门语言,却跟主流编程语言大相径庭,它就是prolog——一门逻辑编程语言。git
prolog 是 Programming in Logic 的缩写,它被普遍应用在人工智能、天然语言等研究领域,使用它来解决逻辑难题彻底不在话下,今天咱们将使用它来解决着名的爱因斯坦逻辑难题(斑马难题),首先让咱们来认识一下 prolog 的语法。github
prolog 中有3种基本元素:事实、规则和查询。事实和规则用于描述数据,查询用于获取问题的答案。
咱们能够这样定义事实:编程
human(lucy).
human(lili).
father(lucy,david).
sister(lucy,lili).
sister(lili,lucy).
这段代码表示 lucy 和 lili 是人类,且她们是姐妹,david 是 lucy 的父亲,继续定义规则:数组
daughter(Father,A,B) :-
father(A,Father), sister(A,B)
这段规则表示对于变量A、B,若是Father变量是A的父亲,且A、B是姐妹,则A、B是Father对象的女儿。
注意,在 prolog 中一个词若以小写开头,那么它是一个固定值,若以大写字母开头,则是一个变量。
将这些事实和规则放在一个文件里面,在命令行下打开 prolog ,对这个文件进行编译,便可提出查询,好比 daughter(david,A,_),prolog 将会求出A可能的取值并输出到控制台,最后的下划线是一个占位符,不会进行求值。ruby
在 prolog 中还可使用递归完成列表和数学等运算,这部分是很强大的,但这里不打算讲,由于有了上面的基础知识后,咱们就能够利用它来解决逻辑问题了,下面就让咱们来解决“斑马难题”吧。编程语言
题目:5个不一样国家且工做各不相同的人分别住在一条街上的5所房子里,每所房子的颜色不一样,每一个人都有本身养的不一样宠物,喜欢喝不一样的饮料。根据如下提示,你能告诉我哪所房子里的人养斑马,哪所房子里的人喜欢喝矿泉水吗?函数
这道题的解题关键在于,要以一种清晰的方式将每一个房子相关的属性(国家、颜色、工做、宠物、饮料、编号)列出来,前面5个提示中包含了5个国家,那么能够利用这一点画出一个表格,每一行表示一个国家,每一列表示房子的一种属性。一步步根据提示获得一些推论,将结果填入表格,答案便渐渐清晰起来,使用这种人工方式推理的结果以下图所示: 人工智能
虽然咱们知道了解题的关键,但这个问题仍然须要通过不少步的推导才能得出结果,若是使用 prolog 那获得这个问题的答案就简单多了,只须要定义好事实和规则,而后向 prolog 提出问题,逻辑引擎就会为咱们查出结果来。spa
下面是解决这个问题的 prolog 代码。
house(A,[A,_,_,_,_]). house(A,[_,A,_,_,_]). house(A,[_,_,A,_,_]). house(A,[_,_,_,A,_]). house(A,[_,_,_,_,A]). right(A,B,[A,B,_,_,_]). right(A,B,[_,A,B,_,_]). right(A,B,[_,_,A,B,_]). right(A,B,[_,_,_,A,B]). middle(A,[_,_,A,_,_]). first(A,[A,_,_,_,_]). neighbor(A,B,[A,B,_,_,_]). neighbor(A,B,[_,A,B,_,_]). neighbor(A,B,[_,_,A,B,_]). neighbor(A,B,[_,_,_,A,B]). neighbor(A,B,[B,A,_,_,_]). neighbor(A,B,[_,B,A,_,_]). neighbor(A,B,[_,_,B,A,_]). neighbor(A,B,[_,_,_,B,A]). attr(Country,Pet,Color,Drink,Work). all_houses(Houses) :- house(attr(britsh,_,red,_,_), Houses), house(attr(spain,dog,_,_,_), Houses), house(attr(japan,_,_,_,painter), Houses), house(attr(italy,_,_,tea,_), Houses), house(attr(norway,_,_,_,_), Houses), first(attr(norway,_,_,_,_), Houses), right(attr(_,_,white,_,_), attr(_,_,green,_,_), Houses), house(attr(_,snail,_,_,photographer), Houses), house(attr(_,_,yellow,_,diplomat), Houses), middle(attr(_,_,_,milk,_), Houses), house(attr(_,_,green,cafe,_), Houses), neighbor(attr(norway,_,_,_,_), attr(_,_,blue,_,_), Houses), house(attr(_,_,_,orange,violinst), Houses), neighbor(attr(_,fox,_,_,_), attr(_,_,_,_,doctor), Houses), neighbor(attr(_,horse,_,_,_), attr(_,_,_,_,diplomat), Houses), house(attr(_,zebra,_,_,_), Houses), house(attr(_,_,_,water,_), Houses).
在事实部分,将房子看作一个总体,描述了房子在5所房子中、房子的左右关系、中间的房子处于什么位置、第一所房子处于什么位置、房子间的相邻关系以及每所房子拥有哪些属性。
规则部分包含了对题目中提示的描述和最终问题的描述,这些定义是为了告诉逻辑引擎,在求值时必须知足这些条件。
最终的查询为 all_houses(A) ,prolog 逻辑引擎将会查找出知足结果的房子数组,注意每所房子由它的属性组成,这样最后获得的结果为:
[attr(norway, fox, yellow, water, diplomat), attr(italy, horse, blue, tea, doctor), attr(britsh, snail, red, milk, photographer), attr(spain, dog, white, orange, violinst), attr(japan, zebra, green, cafe, painter)] .