七周七语言——Prolog(一)

Prolog是一种声明式语言,不同于命令式语言,它基于事实和推论进行逻辑推理。本文介绍了Prolog的基本概念,包括事实、规则和查询,并通过地图着色问题展示其基本推论过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        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。我们来看一下它是怎么得到这个结果的。
  1. 我们发起查询twin_cats(One,Two)。Prolog将One绑定到X,将Two绑定到Y。要处理这个查询,Prolog必须从下述这些目标开始。
  2. 第一个目标是cat(X)。
  3. 我们有两个事实用于匹配,cat(lion)和cat(tiger)。Prolog尝试第一个事实,将X绑定到lion,然后继续下一个目标。
  4. Prolog现在绑定Y到cat(Y)。Prolog使用与处理第一个目标完全相同的办法处理这个目标,选择lion。
  5. 我们已经满足了两个目标,所以这个规则为真。Prolog报告可以让规则为真的One和Two的值,并且报告yes。
有些时候,一个解决方法就足够了,但是有时候一个方法可能不够用。现在可以用“;”符号逐个得到其余的解决方法,也可以输入a获得剩余的所有解决方法
Two=lion?a

One=lion
Two=tiger

One=tiger
Two=lion

One=tiger
Two=tiger

(1 ms)yes

第一天就给大家带来这些了,以后每天会陆续更新读书笔记,跟大家分享,如果你有疑问,请留言,我会尽力解答~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值