Io和Ruby(前两章的语言,后续会补上)被称为命令式语言。命令式语言就是我们需要准确的告诉计算机怎么完成一件任务,每一个细节都需要我们设计好。但是Prolog不同,它是一门声明式语言,我们只需要给他一些事实(fact)和推论(inference),并让他为我们推断。我们不需要告诉电脑怎么做,电脑会自动做出推断。
1 关于Prolog
Prolog是一门逻辑编程语言,它于1972年由Alain Colmerauer和Phillipe Roussel开发完成,在自然语言处理领域颇受欢迎。和SQL一样,Prolog基于数据库,但是其数据有逻辑规则和关系构成;Prolog由两部分组成:一部分用于描述数据,另一部分用于查询数据。下面是基本构建单元。
- 事实。事实是关于真实世界的基本断言。
- 规则。规则是关于真实世界中一些事实的推论。
- 查询。查询是关于真实世界的一个问题。
下面我们来具体看一看Prolog的语法规则,揭开它的神秘面纱。
2 基本概况
Prolog中,第一个字母的大小写有重要含义,如果一个词以小写字母开头,他就是一个原子(atom)—— 一个类似ruby符号的固定值,如果一个词以大写字母或下划线开头,那么他就是一个变量。变量的值可以改变,但是原子不能。下面看个具体的例子,可以帮助我们理解这两个概念。
likes(wallace,cheese).
likes(grommit,cheese).
likes(wendolene,sheep).
friend(X,Y):-\+(X=Y),likes(X,Z),likes(Y,Z).
这几行代码可以这样理解:前三行语句是事实,最后一行语句是一个规则。wallace,grommit,wendolene都是原子。我们可以这么说,wallace喜欢cheese,grommit喜欢cheese,wendolene喜欢sheep。现在我们可以问一些问题了,Prolog会用yes或no来回答。比如:
|?-likes(wallace,sheep).
no
|?-likes(grommit,cheese).
yes
这两个问题都很好理解,wallace喜欢sheep吗?(No.)grommit喜欢cheese吗?(Yes.)
3 基本推论
我们来测试一下friend规则:
|?-friend(wallace,wallace).
no
在规则中,如果X是Y的朋友,那么X就不可能与Y相同。看看:-右边的第一部分吧,这部分被称为一个子目标。\+执行逻辑取反操作,这样\+(X=Y)的意思就是X不等于Y。
再来做一些查询:
|?-friend(grommit,wallace).
yes
|?-friend(wallace,grommit).
yes
深入分析一下这几行代码:首先X不等于Y,满足第一个子目标。查询将使用第二个和第三个子目标:likes(X,Z)和likes(Y,Z)。grommit和wallace都喜欢cheese,所以满足了第二个和第三个子目标,返回yes。
下面来正式介绍一下这个术语:friend(X,Y):-\+(X=Y),likes(X,Z),likes(Y,Z).我们把这个规则称作friend/2,即有两个参数的friend规则的缩写。这个规则拥有三个用逗号(可以理解为“与”)分隔的子目标。当所有子目标为真时,这个规则才是真。
4 填空
我们还可以使用逻辑引擎为一个查询找出所有可能的匹配。为此,我们需要在查询中指定一个变量。考虑下面知识库:
food_type(velveeta,cheese).
food_type(ritz,cracker).
food_type(spam,meat).
food_type(sausage,meat).
food_type(jolt,soda).
food_type(twinkie,dessert).
flavor(sweet,dessert).
flavor(savory,meat).
flavor(savory,cheese).
flavor(sweet,soda).
food_flavor(X,Y):-food_type(X,Z),flavor(Y,Z).
我们给出一些事实,如food_type(velveeta,cheese),意思是一种食物有一定的类型。另外一些如flavor(sweet,dessert),意思是一种食物类型有特有的味道。最后我们给出一个名为food_flavor的规则,它可以推断出食物的味道。如果食物X属于Z类食物且Z也具有味道Y,则食物X具有food_flavor Y。 我可以问一些问题:
|?-food_type(What,meat).
What=spam?;
What=sausage?;
no
我们请求Prolog,“找出一些满足查询food_type(What,meat)的值。”Prolog找到了一个spam(注意,这里的What是一个变量,你可以用任意一个变量代替他,只要是以大写字母开头)。输入;,请求下一个,他返回了sausage。接下来,请求另一个值,返回no。这里有些诡异,为方便起见,如果在剩余部分中Prolog检测不到其他可选项,你将看到一个yes。如果Prolog在未经更多计算的情况下不能立刻判定是否还有更多选项,那么他将提示你查询下一个并返回no。(这里不是很理解,它是想说如果Prolog在短时间内不能查询到结果,就返回no,以便不让程序员久等?但是这不能说明没有满足要求的结果?如果读者看懂了,希望给我留言,解答我的困惑,3Q

我们也可以让Prolog把各种事实串到一起:
|?-food_flavor(What,savory).
What=velveeta?;
What=spam?;
What=sausage?;
no
(1) 地图着色
我们要给美国东南部的地图着色(图略),我们不想两个接壤的州具有相同的颜色。
different(red,green).different(red,blue).
different(green,red).different(freen,blue).
different(blue,red).different(blue,green).
coloring(Alabama,Mississippi,Georgia,Tennessee,Florida):-
different(Mississippi,Tennessee),
different(Mississippi,Alabama),
different(Alabama,Tennessee),
different(Alabama,Mississippi),
different(Alabama,Georgia),
different(Alabama,Florida),
different(Georgia,Florida),
different(Georgia,Tennessee).
我们有三种颜色,对五个州着色。在coloring规则中,告诉Prolog中各个州(用五个不同的变量表示州)的接壤关系。下面我们测试一下:
|?-coloring(Alabama,Mississippi,Georgia,Tennessee,Florida).
Alabama=blue
Florida=green
Georgia=red
Mississippi=red
Tennessee=green?
也可以输入a得到另外几种着色组合。
5 合一,第一部分
考虑下面的知识库:
cat(lion).
cat(tiger).
dorothy(X,Y,Z):-X=lion,Y=tiger,Z=bear.
twin_cats(X,Y):-cat(X),cat(Y).
|?-dorothy(lion,tiger,bear).
yes
在这个例子中,=意为合一,或者说使等号两侧相同(本人理解类似于java中的==)。合一的意思就是“找出那些使规则两侧匹配的值”。在右侧,Prolog将X、Y和Z分别绑定为lion、tiger和bear。这些值与左侧相应的值匹配,所以合一是成功的。我们为他再增加点趣味,合一在规则的两侧都能工作。
|?-dorothy(One,Two,Three).
One=lion
Three=bear
Two=tiger
yes
这个例子多了一个间接层。在子目标中,Prolog使得X、Y和Z分别与lion、tiger和bear合一。在左侧,Prolog使得X、Y和Z分别与One、Two和Three合一,然后报告结果。
然后,让我们试一下最后那条规则twin_cats/2。
|?-twin_cats(One,Two).
One=lion
Two=lion?
Prolog报告了第一种可能。lion和lion都是cat。我们来看一下它是怎么得到这个结果的。
- 我们发起查询twin_cats(One,Two)。Prolog将One绑定到X,将Two绑定到Y。要处理这个查询,Prolog必须从下述这些目标开始。
- 第一个目标是cat(X)。
- 我们有两个事实用于匹配,cat(lion)和cat(tiger)。Prolog尝试第一个事实,将X绑定到lion,然后继续下一个目标。
- Prolog现在绑定Y到cat(Y)。Prolog使用与处理第一个目标完全相同的办法处理这个目标,选择lion。
- 我们已经满足了两个目标,所以这个规则为真。Prolog报告可以让规则为真的One和Two的值,并且报告yes。
有些时候,一个解决方法就足够了,但是有时候一个方法可能不够用。现在可以用“;”符号逐个得到其余的解决方法,也可以输入a获得剩余的所有解决方法。
Two=lion?a
One=lion
Two=tiger
One=tiger
Two=lion
One=tiger
Two=tiger
(1 ms)yes
第一天就给大家带来这些了,以后每天会陆续更新读书笔记,跟大家分享,如果你有疑问,请留言,我会尽力解答~