Learn Prolog Now 翻译 - 第一章 - 事实,规则和查询 - 第一节, 一些简单的例子

 该系列文章是网上的Prolog学习资料:www.learnprolognow.org的中文翻译。希望能够通过翻译此学习资料,达到两个目的:第一、系统学习prolog的知识;第二、提升英文文章理解

和翻译能力。

内容摘要:

给出一些Prolog编程的简单例子;

Prolog的基本结构:事实,规则和查询;

环境说明:

本系列文章使用的Prolog运行环境是:SWI-Prolog,官网地址是:http://www.swi-prolog.org

Prolog中只有三种基础结构:事实(facts),规则(rules)和查询(queries)。事实和规则的集合称为知识库(knowledge base)(或者称为数据库,为了和传统意义上的数据库进行区分,

统一使用知识库),Prolog的编程几乎就是在编写知识库。换种说法,Prolog编程基本上等于编写知识库,由事实和我们感兴趣的一些关系组合而成的规则构成。

那么如何使用Prolog程序呢?通过查询,即通过问一些问题,这些问题的信息和答案是存储在知识库中的。

可能听上去很奇怪,这和传统意义上的编程似乎没有什么关系,毕竟编程应该是告诉计算机做什么的吧?但是我们将会看到,Prolog的编程方式是非常有意义的,至少在特定的领域;比如计算机

语言学和人工智能领域。让我们进入具体编写一些简单知识库的实践,在学习Prolog的过程中,实践是最好也是唯一的方法。

Knowledge Base 1

Knowledge Base 1 (KB1)只是一些简单事实的集合。事实是指无条件为真的一些状态或者关系。比如:我们可以定义Mia,Jody和Yolanda是女士,Jody在弹吉他,然后有一个聚会,

在Prolog中,可以定义下面5个事实:(注意每个事实的定义都是使用英文字符的句号作为结束标识符)

woman(mia).
woman(jody).
woman(yolanda).
playsAirGuitar(jody).
party.

上面的事实集合就是KB1,是我们第一个关于Prolog编程的例子。注意,上面提及的名字mia,jody,yolanda,她们的women属性(可以先这么理解)和弹吉他,及其聚会,都是小写字母开头,我们

稍后会详细解释其中的原因。

如何使用KB1呢?通过查询。即,通过查询一些KB1包括的信息来使用KB1。下面是一些例子,比如我们通过下面的查询可以问Prolog,Mia是不是一位女士:

?- women(mia).

Prolog会回答:yes

因为在KB1中明确地定义了women(mia)的事实,所以Prolog的答案是yes。注意,在实际使用Prolog查询的时候,我们不需要显式输入?-,这个Prolog(可能不同的Prolog解释器会略有不同)是待输

入符号。在查询语句的最后,一定要输入英文句号作为结束符,如果没有输入,那么Prolog不会执行查询操作,而是一直等待。

类似地,我们可以通过下面的查询语句问Prolog,jody是否弹吉他:

?- playsAirGuitar(jody).

Prolog同样会问答:yes,因为这也是KB1中的一个事实。但是,如果我们尝试问Mia是否弹吉他:

?- playsAirGuitar(mia).

Prolog会回答:no,因为这不是KB1中的事实,而且KB1很简单,其他事实也不能推导出这个结论,所以Prolog认为playsAirGuitar(mia)在KB1中不能成立。

下面是两个重要的例子。首先,如果我们这样查询:

?- playsAirGuitar(vincent).

Prolog又会回答no。为什么?因为这个查询中提及的Vincent这个人,在KB1中没有信息,所以Prolog认为KB1中不能推导出关于他的任何其他信息。类似的,如果我们这样查询:

?- tatooed(jody).

Prolog同样会回答no。为什么?因为这个查询中提及的tatooed这个属性,在KB1中没有信息,所以Prolog认为不能推导出这个属性相关的任何其他信息。

无需多说,我们可以查询关注的属性,比如:

?- party.

Prolog会回答yes。如果我们查询:

?- rockConcert.

Prolog会回答no,和我们的期望是一致的。

Knowledge Base 2

下面是KB2,我们的第二个知识库的定义:

happy(yolanda).
listen2Music(mia).
listen2Music(yolanda) :- happy(yolanda).
playsAirGuitar(mia) :- listen2Music(mia).
playsAirGuitar(yolanda) :- listen2Music(yolanda).

在KB2中,有两个事实:listen2Music(mia)和happy(yolanda),剩下的三个都是规则。Prolog中的规则是有条件为真的一些状态或者关系。比如规则一可以这么理解:Yolanda听音乐如果

Yolanda很高兴,最后一个规则可以这么理解:Yolanda弹吉他如果Yolanda听音乐。更抽象地理解,符号:-理解为“如果”,或者“以什么为前提”。在:-左边的部分是规则的头部,在:-右边的部分

是规则的主干,所以规则可以这么理解:如果一个规则的主干为真,那么这个规则的头部也为真。所以,以下是Prolog规则运用的要点:

如果知识库包括了一个规则,head :- body,并且Prolog知道在知识库中,body部分为真,那么Prolog就能够推导head为真。推导的基础步骤称为假言推理(modus ponens)。

让我们继续看具体的例子,如果我们查询Mia是否弹吉他:

?- playsAirGuitar(mia).

Prolog会回答yes,为什么?毕竟在KB2中,playsAirGuitar(mia)不是一个事实,但是可以找到关于它的一个规则:

playsAirGuitar(mia) :- listen2Music(mia).

可以明确知道,KB2中包含了listen2Music(mia)的事实。所以Prolog可以使用规则的假言推理推导出playsAirGuitar(mia)为真。

下面另外一个例子显示,Prolog可以使用假言推理链,如果我们查询:

?- playsAirGuitar(yolanda).

Prolog会回答yes,为什么?首先,通过使用happy(yolanda)的事实,及其相关的规则:

listen2Music(yolanda) :- happy(yolanda).

Prolog可以推导出一个新的事实:listen2Music(yolanda)。这个新事实在知识库中是隐式存在的(通过推导得出),但是,Prolog可以像使用显式的事实一样使用它。接下来,通过这个推导的

事实及其规则:

playsAirGuitar(yolanda) :- listen2Music(yolanda).

Prolog可以推导中新的事实:playsAirGuitar(yolanda),即我们的查询结果为真。总结一下:一个假言推理的任何事实,可以用作其他规则的输入,通过链接的方式,将所有的假言推理应用组合

起来,Prolog就可以从知识库中包含的事实和规则中推导出任何符合逻辑的信息。

在知识库中的事实和规则统称为子句(clauses)。所以KB2包括了5个子句,其中有3个规则和2个事实。另外一种看待KB2的方式可以这么说,它是由3个谓词(predicates)(或者成为procedures)

组成,三个谓词是:listen2Music,happy,playsAirtGuitar。

其中happy谓词由一个独立的子句(一个事实)组成。listen2Music和playsAirGuitar谓词分别由两个子句(listen2Music两个子句一个是事实,另外一个是规则;playsAirGuitar两个子句都是规

则)组成。可以认为Prolog编程就是由谓词构成的。本质上来说,谓词的概念很重要,编程中各种子句都是关于谓词代表的含义及其推导的含义。

还有一点可以提及的是,我们可以把事实看着没有主干的规则,即我们可以认为事实是无论任何条件都成立的规则。

Knowledge Base 3

KB3,我们的第三个知识库,由5个子句组成:

happy(vincent).
listen2Music(butch).

playsAirGuitar(vincent) :-
    listen2Music(vincent),
    happy(vincent).

playsAirGuitar(butch) :-
    happy(butch).

playsAirGuitar(butch) :-
    listen2Music(butch).

KB3中定义了两个事实,happy(vincent)和listen2Music(butch),及其三个规则。KB3中的定义了三个名字和KB2中一样的谓词(happy,listen2Music,和playsAirGuitar),但是其实现不同,

特别是在playsAirGuitar的谓词中引入了一些新的含义。首先,分析这个规则:

playsAirGuitar(vincent) :-

    listen2Music(vincent),

    happy(vincent).

其中主干部分有两项,或者说两个目标组成。这里最重要的是英文逗号字符,它分隔了目标listens2Music(vincent)和目标happy(vincent)。这是逻辑与在Prolog中的表现形式。所以,可以这么

理解:“Vincent弹吉他如果他听音乐并且他很快乐”。

所以,如果我们查询:

?- playsAirGuitar(vincent).

Prolog会回答no。这是因为,KB3包含happy(vincent)的事实,但是没有明确地包含listen2Music(vincent),并且listen2Music也不能被推导出来。所以KB3只能满足playsAirGuitar(vincent)

两个条件之一,所以查询失败,Prolog回答no。

顺便提及一下,空格在Prolog中是没有意义的,比如,我们也可以这么书写:

playsAirGuitar(vincent) :-

    happy(vincent),

      listen2Music(vincent).

这个和之前的定义是同样效果。Prolog提供了很高的书写自由度,便于我们书写出可读性高的程序代码。

接下来,分析KB3中有相同头部的两个规则:

playsAirGuitar(butch) :- happy(butch).

playsAirGuitar(butch) :- listen2Music(butch).

这里表达的意思是,Butch弹吉他如果他听音乐,或者他很高兴。即,多个有相同头部的规则是Prolog中逻辑或的表达方式。所以,如果我们查询:

?- playsAirGuitar(butch).

Prolog会回答yes。虽然第一个规则对于这个查询没有作用(因为happy(butch)在KB3中不存在,也不能被推导),但是KB3包含了listen2Music(butch),所以Prolog可以使用假言推理:

playsAirGuitar(butch) :- listen2Music(butch).

推导中playsAirGuitar(butch)。

Prolog中存在另外一种方式表示逻辑或,可以使用如下的定义来替代之前的两个规则:

playsAirGuitar(butch) :-

    happy(butch);

    listen2Music(butch).

英文分号字符在Prolog中也表示逻辑或,所以这个单一规则的含义,和之前两个规则的含义是相同的。那么使用多个规则,还是使用英文分号,哪个更好呢?这个需要根据情况来判断。一方面,

使用分号会让Prolog代码的可读性变差,但是另一方面,使用分号后规则数量变少,使得处理效率更好。

在上面的学习中,可以看出Prolog中明确包括了很多逻辑标识,比如,:-表示“如果”;英文字符逗号“,”表示逻辑与;英文字符分号“;”表示逻辑或。而且,我们可以看到标准的逻辑证明规则

(假言推理)在Prolog中起到了重要作用。所以,我们可以开始理解,为什么“Prolog”这个名字是“Programming with logic”的简写了,:)。

Knowledge Base 4

下面是KB4,我们的第四个知识库的定义:

woman(mia).
woman(jody).
woman(yolanda).

loves(vincent, mia).
loves(marsellus, mia).
loves(pumpkin, honey_bunny).
loves(honey_bunny, pumpkin).

哈哈,这是一个相当无聊的知识库。这里没有规则,只有事实的集合。当然,我们可以第一次接触一个谓词关系中存在两个名字(这里指loves定义的关系)。

但是事实并非如此,这个例子的新意不在于知识库的定义,而是我们查询的方式。事实上,这是我们第一次接触Prolog的变量使用,如下:

?- woman(X).

X即代表一个变量(在Prolog中,大写字母开头的单词代表变量,这也是为什么我们之前的例子中,所有出现的字符都是小写字母开头的原因)。这里X不是一个具体的名字,它更像一个信息的占位

符号。即,这个查询就是问Prolog:告诉我们你知道都有哪些人是女士(woman)?

Prolog通过在KB4中从上至下遍历来回答这个查询,Prolog会试图找到(或者匹配)表达式woman(X)的信息。在KB4中,第一个事实是woman(mia),所以Prolog会将X和mia合一,这样可以完美地符

合查询(顺便提及一下,这个处理流程中Prolog做了很多的操作:我们可以简单地理解为,Prolog将X初始化为mia,或者将X值绑定成mia)。Prolog会将结果返回,如下:

X = mia

这里不仅仅说至少有一个满足查询的结果存在于KB4中,而且明确地告诉了这个结果值。这里Prolog不是回答yes,而是实际给出能够满足查询的变量绑定(变量初始化)。

但是,这不是结束。变量的要点是它们能够代表,或者说能够合一不同的符合查询的信息。而且有其他的women在知识库中,也满足这个查询。所以,我们可以输入英文字符”;“继续查询下一个匹配

的结果:

X = mia;

因为英文字符”;“代表是逻辑或,所以这个查询可以理解为:还有其他结果吗?所以Prolog有会继续遍历知识库(它会标记上一次结果的地点,并且从那里继续),寻找下一个可能的结果,并且找到

jody也满足,所以Prolog会回答:

X = mia;

X = jody

这里就告诉了我们基于KB4第二个符合查询的结果值。当然,如果我们继续输入英文字符”;“,Prolog会继续回答:

X = mia;

X = jody;

X = yolanda

但是当我们第三次输入英文字符”;“会发生什么?Prolog会回答no,没有其他合一的可能了。因为在KB4中没有women开头的事实了,剩余的4个规则都是关于loves关系的,所以没有办法再对woman(X)

进行合一。

接下来,我们尝试一个更为复杂的查询,如下:

?- loves(marsellus, X), woman(X).

前面已经介绍过,英文字符逗号“,”表示逻辑与,所以这个查询的含义是:是否有这样的X,它既能够满足Marsellus爱它,并且还是一名女士?如果你再看知识库,会发现:Mia是一名女人(事实一)

,同时Marsellus爱Mia(事实5)。Prolog能够模拟这个能力,把结果找出来。即Prolog能够遍历整个知识库,并将X和Mia合一,使得我们查询中的两个子查询都满足。最后,Prolog会回答:

X = mia

能够将变量和知识库中的信息进行合一是Prolog的核心。随着我们的深入学习,我们会发现很多Prolog的有趣思想——但是Prolog能够进行合一并返回变量绑定信息的能力是所有这一切的关键点。

Knowledge Base 5

好的,我们之前介绍了变量,但是仅仅是在查询中使用到。其实变量也可以应用在知识库中。而且只有这样做,我们才能写出真正有用的Prolog程序。下面是一个简单的例子,知识库KB5的定义:

loves(vincent, mia).
loves(marsellus, mia).
loves(pumpkin, honey_bunny).
loves(honey_bunny, pumpkin).

jealous(X, Y) :- loves(X, Z), loves(Y, Z).

KB5包含了4个loves关系的事实和一个规则,这个规则是我们至今定义的最有趣的一个:它包括了三个变量(X,Y,Z),这个规则如何理解?

本质上来说,这个规则定义“情敌”的概念。可以这里理解,如果X爱Z,同时Y也爱Z,那么X和Y就是情敌(呵呵,这里的情敌仅仅限于学习,现实情况会复杂的多,:))。关键的一点在于这是一个

通用的陈述,其中不涉及具体的人,比如mia,pumpkin等——从某种程度来说,是指世界上的每个人。这就是抽象。

如果我们进行查询:

?- jealous(marsellus, W).

这个查询的含义是:是否存在这样的一个人W,他和Marsellus是“情敌”?Vincent就是这个人。如果你检查“情敌”的定义,你可以发现Marsellus和Vincent就是“情敌”,因为他们两个人都爱

同样的一个女士,即Mia。所以Prolog会回答:

W = vincent

时间: 2024-11-03 17:36:02

Learn Prolog Now 翻译 - 第一章 - 事实,规则和查询 - 第一节, 一些简单的例子的相关文章

Learn Prolog Now 翻译 - 第二章 - 合一和证明查询树 - 第一节, 合一

内容提要: 合一的定义: 一些合一的例子: 触发校验: 使用合一编程: 合一的定义 在上一章的知识库KB4中,我们简单地提及了合一的思想.比如,Prolog将woman(X)和woman(mia)合一,所以把变量X初始化为mia.现在是时候更加细致地研究合一,因为合一是 Prolog中最为基础的思想. 回顾一下Prolog中的三种语句类型: 1. 常量,可能是原子(比如vincent)或者是数字(比如24). 2. 变量,比如X,Z3,List等. 3. 复杂语句,形式为:functor(ter

Learn Prolog Now 翻译 - 第二章 - 合一和证明搜索 - 第二节, 证明搜索

证明搜索 上一节我们已经学习了合一,本节我们继续学习Prolog是如何通过搜索知识库去决定输入的查询是否能够满足.我们将会学习证明搜索,并通过简单的一个例子去涵盖这个基础的概念. 假设我们有如下的知识库: f(a). f(b). g(a). g(b). h(b). k(X) :- f(X), g(X), h(X). 如果我们查询: ?- k(Y). 这个查询的结果十分明显,即k(b),但是Prolog是如何将其求解出的了?让我们继续看. Prolog读入整个知识库,然后尝试将查询k(Y)和知识库

Learn Prolog Now 翻译 - 第二章 - 合一和证明搜索 - 第三节, 练习题和答案

练习题 2.1 下面各组语句中,哪些组是能够合一的?如果能够合一,请给出变量初始化的信息. 1. bread = bread. 2. 'Bread' = bread. 3. 'bread' = bread. 4. Bread = bread. 5. bread = sausage. 6. food(bread) = bread. 7. food(bread) = X. 8. food(X) = food(bread). 9. food(bread, X) = food(Y, sausage).

Learn Prolog Now 翻译 - 第一章 - 事实,规则和查询 - 第二节, Prolog语法介绍

内容摘要: 原子(Atom) 数字(Numbers) 变量(Variables) 复杂语句(Complex Terms) 通过上一节的学习,我们已经大概熟悉了Prolog的编程思路,这一节我们会回过头,详细学习其中的一些语法细节.首先,问一个基础的问题:我们已经在Prolog程序中看到了很多类型的表达式 (比如,jody,playsAirGuitar(mia),和X),但这些仅仅只是例子,是时候更加深入了,到底事实.规则和查询是由什么构成的? 答案就是语句(terms),在Prolog中一共存在

Learn Prolog Now 翻译 - 第三章 - 递归 - 第一节,递归的定义

在Prolog中,谓词可以递归地定义.简要地讲,一个谓词是递归定义的,如果一个或者多个规则的定义中包含了规则自身. 例子1:消化 考虑如下的知识库: is_digesting(X, Y) :- just_ate(X, Y). is_digesting(X, Y) :- just_ate(X, Z), is_digesting(Z, Y). just_ate(mosquito, blood(john)). just_ate(frog, mosquito). just_ate(stork, frog

Learn Prolog Now 翻译 - 第五章 - 数字运算 - 第一节,Prolog中的数字运算

内容提要 Prolog中的数字运算 Porlog运算的本质 Prolog中的数字运算 Prolog语言本身提供了一些基础的运算符号,对整数进行一些操作(即类似...-3, -2, -1, 0, 1, 2, 3等).多数Prolog的实现同时也提供了一些工具对实数进行操作 (比如浮点数,1.53,6.35,等等).但是我们不会讨论浮点数,因为浮点数在典型的Prolog应用中很少,所以不是本文的重点.但是另一方面,整数是在Prolog 中有典型应用场景的(比如记录列表的长度),所以掌握起应用是十分重

Learn Prolog Now 翻译 - 第四章 - 列表 - 第二节,列表成员

内容提要 本章主要介绍使用递归操纵列表的一个实际例子:判断一个元素是否在包含在一个列表中. 是时候介绍第一个Prolog中通过递归操纵列表的程序例子了.我们最感兴趣的事情之一是,某个对象是否是列表中的元素.所以,我们想写一个程序,当假设输入是一个对象X和一个列表L, 得出结果是X是否属于L.这个程序的名字通常是:member,是Prolog程序中使用递归操纵列表最简单的例子,如下: member(X, [X|T]). member(X, [H|T]) :- member(X, T). 这就是全部

Learn Prolog Now 翻译 - 第四章 - 列表 - 第三节,递归遍历列表

内容提要 通过递归对列表进行遍历,从而完成各种操作. member/2这个谓词逻辑通过递归遍历了列表,对列表头部有一些操作,然后递归地对列表尾部做另外一些相同的操作.通过递归遍历列表在Prolog是十分普遍的做法, 事实上,我们必须要掌握这项技能.所以我们学习如下的例子. 当我们使用列表的时候,我们经常会将一个列表和另一个列表进行对比,或者拷贝一个列表的内容到另一个列表去,或者翻译一个列表到内容到另一个列表去,或者 类似到一些操作.这里有一个例子,假设我们有一个谓词a2b/2,有两个参数,第一个

Learn Prolog Now 翻译 - 第一章 - 事实,规则和查询 - 第三节, 练习题和答案

练习题 1.1 下面的字符序列哪些是原子,哪些是变量,哪些两者都不是? 1. vINCENT 2. Footmassage 3. variable23 4. Variable2000 5. big_kahuna_burger 6. 'big kahuna burger' 7. big kahuna burger 8. 'Jules' 9. _Jules 10. '_Jules' 我的答案: vINCENT,variable23,big_kahuna_burger,'big kahuna burg