• 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会回答:true

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

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

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

     ?- playsAirGuitar(jody).

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

     ?- playsAirGuitar(mia). 

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

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

     ?- playsAirGuitar(vincent).

     Prolog又会回答false。为什么?因为这个查询中提及的vincent这个人,在KB1中没有与之相关的任何信息,所以Prolog认为KB1中不能推导出关于他的任何其他信息。

     类似的,如果我们这样查询:

     ?- tatooed(jody).

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

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

     ?- party.

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

     ?- rockConcert.

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

     

    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会回答true,为什么?毕竟在KB2中,playsAirGuitar(mia)不是一个事实,但是可以找到关于它的一个规则:

     playsAirGuitar(mia) :- listen2Music(mia).

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

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

     ?- playsAirGuitar(yolanda).

     Prolog会回答true,为什么?首先,通过使用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会回答false。这是因为,KB3包含happy(vincent)的事实,但是没有明确地包含listen2Music(vincent),并且也不能被推导出来。所以KB3只能满足playsAirGuitar(vincent)

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

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

     playsAirGuitar(vincent) :- 

        happy(vincent),

          listen2Music(vincent).

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

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

     playsAirGuitar(butch) :- happy(butch).

     playsAirGuitar(butch) :- listen2Music(butch).

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

     ?- playsAirGuitar(butch).

     Prolog会回答true。虽然第一个规则对于这个查询没有作用(因为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不是回答true,而是实际给出能够满足查询的变量绑定(变量初始化)。

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

    继续查询下一个匹的结果:

     X = mia;

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

    的结果,并且找jody也满足,所以Prolog会回答:

     X = mia;

     X = jody

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

     X = mia;

     X = jody;

     X = yolanda

     但是当我们第三次输入英文字符”;“会发生什么?Prolog会回答false,没有其他合一的可能了。因为在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

  • 相关阅读:
    C# Xamarin For Android自动升级项目实战
    C# Xamarin移动开发基础进修篇
    .NET轻量级ORM框架Dapper入门精通
    ASP.NET WebApi技术从入门到实战演练
    (简单、可靠的安装方法)在Windows Server2016中安装SQL Server2016
    ASP.NET (Core) WebAPI IIS PUT和DELETE请求失败 405的解决办法
    js中判断对象是否为空的三种实现方法
    windows10如何设置只显示时间不显示日期
    NuGet微软官方中国国内镜像
    Win10找不到hosts文件解决方法
  • 原文地址:https://www.cnblogs.com/seaman-h-zhang/p/4592913.html
Copyright © 2020-2023  润新知