Category Archives: Prolog学习笔记

学习Prolog,主要是Hyry的《Prolog与人工智能》留下的笔记。

在SICStus中,是不能直接使用append这个谓词的,虽然在Amzi和SWI Prolog中这个都作为内建谓词,但是SICStus中,使用append需要先加载lists包。

原话是这样的:

This package defines operations on lists. Lists are a very basic data structure, but nevertheless certain very frequent operations are provided in this package.

这个package定义了列表的操作符,列表时一个非常基本的数据类型,不过一些非常常用的操作符在这个package中提供。

需要加载这个包,输入use_module(library(lists)).
这样就可以使用append/3、delete/3、is_list/1、last/2、max_list/2等有关列表的谓词了。

clip_image001

参考资料:

The Prolog Dictionary: http://www.cse.unsw.edu.au/~billw/prologdict.html
SICStus User’s Manual: http://www.sics.se/sicstus/docs/latest4/html/sicstus.html/ Read More →

在列表一节中,作者用了这样的方法来定义谓词:

member(H,[H|T]).
member(X,[H|T]):-member(X,T).

递归是显然的,但它是用什么方法完成的这个过程的呢?不理解的童鞋可以听我下面的讲解:^_^

首先,对于不理解的程序,最直接的办法莫过于调试,单步跟一遍,下面是SCIStusmember(c, [a, b, c, d])的单步跟踪结果:

% trace

| ?- member(c, [a, b, c,d]).

       1      1 Call: member(c,[a,b,c,d]) ?

       2      2Call: member(c,[b,c,d]) ?

       3      3Call: member(c,[c,d]) ?

?       3      3 Exit: member(c,[c,d]) ?

?       2      2 Exit: member(c,[b,c,d]) ?

?       1      1 Exit: member(c,[a,b,c,d]) ?

Yes

可以看到Prolog很聪明的理解了我们的目的,一步一步向前推,先看c是不是[a, b, c, d]的表头,不是,再看是不是[b, c, d]的表头,最后再看是不是[c, d]的表头,发现是,于是就退出来了,返回一个yes

那么在这个过程里,H,[H|T] 是怎么起作用的呢?其实我们可以这么想,member是一个二元谓词,所以可以把它写成member(Var1, Var2),在这里,我们输入的第一个变量Var1 = H,而第二个变量 Var2
则用“=”运算符与[H | T]做运算,注意是做运算,或者说是比较 Var2[H | T] 是否相等,如果带入刚才我们定义的Var1,那就是比较 Var2 [Var1 | T]是否相等,因为我们对T没有做什么约束,甚至可以是空——“[]“,所以表达式的真值就取决于Var1是否是是 Var2的表头,又因为这个谓词没有定义什么其他内容,所以这个真值就是谓词的真值。

写得有点乱,写个例子大家就明白了:

对于member(c, [a,b, c, d])

(0) 假定原型为 member( Var1, Var2 ).

% 下面的执行内容为member(H,[H|T]).

(1)Var1 = c.

(2)Var2 = [a, b, c, d].

(3)Var2 = [Var1 | T].

     [a, b, c, d] = [ c | [b, c, d] ].    %注意这是个判断

(3) 表达式返回 false.

(4) 谓词返回 false.

%下面执行内容为member(X,[H|T]):- member(X,T).

(4)Var1 = c.

(5)Var2 = [a, b, c, d].

(6)Var2 = [H | T]

      H = a, T = [b, c, d].

(7)member(Var1, T)

      member(c, [b, c, d]).

% 下面的执行内容为member(H,[H|T]).

(8)Var1 = c.

(9)Var2 = [b, c, d].

(10)Var2 = [Var1 | T].

     [b, c, d] = [c | [c, d] ].

(11) 表达式返回false.

(12) 谓词返回 false.

%下面执行内容为member(X,[H|T]):- member(X,T).

(13)Var1 = c.

(14)Var2 = [b, c, d].

(15)Var2 = [H | T]

      H = b, T = [c, d].

(16)member(Var1, T).

     member(c, [c, d])

% 下面的执行内容为member(H,[H|T]).

(16)Var1 = c.

(17)Var2 = [c, d].

(18)Var2 = [Var1 | T].

     [c, d] = [c | [d] ].

(19) 表达式返回true.

(20) 谓词返回true.

理解了这个过程,我们就可以把这个member函数写的再清晰一些:

member_m(H, T) :- [X | Y] = T, X = H.

member_m(H, T) :-

  [X | T] = T,

  member_m(H, T).

% Well, this is my
understaning of member/
2

Read More →

好吧,我承认我应该用Amzi而不是SICStus,在使用not这个“内部谓词”时,SICStus又报错了,经查找资料,因为只用not来声明非真或者对证明结果取反容易混淆——这导致解释器会花时间来理解这个not究竟是什么意思,所以现代的Prolog使用”\”或”\+”,其中”\”用于声明,”\+”用于取反。不过当前的编译器也趋于支持not——为了支持旧的代码,比如经测试Amzi就对新旧两种方法均支持。不过看起来似乎新方法比较科学呢^_^.

P.S.如果有人不理解”\”或”\+”,可以尝试类似下面的语句:

\ 2=4.

\+ 2=4.

参考资料: http://www.cse.unsw.edu.au/~billw/prologdict.html#negation

Read More →

教程中的例子使用的是Amzi来编译。我用的则是SICStus,但是在试验本节中的语句时出现了“Permission error: cannot retract static user:here/1”的问题,修改解释器的Language为SICStus或ISO均出现此问题,觉得应该是解释器不同造成的差异,于是在Amzi下试验,发现运行正常,后经在网上查找资料,发现SICStus中Consult后的谓词语句都是静态的,如果想对其进行动态的修改,需要用dynamic修改原文件。

比如在本例中,需要在:

here(kitchen).

前增加如下语句:

:- dynamic here/1.

即(见图1):

:- dynamic here/1.
here(kitchen).

这样在SICStus就可以成功执行goto/1了(见图2)。

clip_image001

图1 pro文件

clip_image002

图2 运行效果

Read More →

0.导言

因为学习人工智能的关系,最近需要学习Prolog,看的主要指导教程是Hyry的《Prolog和人工智能》[1],译自Amzi Prolog的帮助文件,这本书虽然在开头处推荐了Amzi Prolog作为编程环境,但是我作为一个被Visual Studio,Matlab惯坏的人,实在是无法习惯Amzi Prolog简陋的环境——它的编辑器没有语法高亮功能,没有自动缩进,更不要提什么自动补全或者查看定义这类的高级功能了,当然,Prolog这个语言比较特殊,像那些功能也确实比较难以实现,但是为什么解释器居然都不能按”↑”键来转到上一条命令,而且如果我”()”成对得打然后再在里面插字符还会报错?太坑了吧。

在网上搜索了下,有人推荐了七种Prolog的解释器/编译器[2],还有一篇文章比较了三种开源Prolog解释器[3],大致看了下,第一篇里面大力推荐了SICStus,好吧,下下来安装后发现,好吧,这仅仅是个解释器,和我理想中的IDE完全不搭界,而且那种惨白色的背景,而且还不支持必要的快捷键,但是好处是,起码可以用”↑”键来转到上一条命令,而且终于能让我成对的打”()”然后向里面插入字符了,此外,它的运行结果比Amzi Prolog要好看。除了上面两个,还看了下Visual Prolog,好吧,终于看到一个靠谱的IDE,可是,他是商业软件虽然有免费版,但是它的相关资源很丰富,特别是中文资源,不过在VanHeising的文章里说它使用相对复杂[1],介于现在是初学,所以还是先不要用那么专业的好了*……如果,出现什么解释器不同造成的编译错误,初学者往往很难处理。此外,Swi Prolog的界面看起来也不错,而且还有一个J-Prolog Editor可以作为Swi Prolog的编辑器[4],但是,VanHelsing和David都指出了Swi Prolog速度偏慢[2,3],所以也舍弃了,另外还有GNU Prolog,但是官方页面提供的下载链接无法成功下载[5],所以懒得试了。

在这么反复折腾之后最终决定还是自己搭建一个环境吧,关键是编辑器,因为解释器的话其实SICStus也就足够了。

脚注:
* Visual Prolog界面好看,中文资源丰富,其实是个不错的选择,当然介于Hyry的《Prolog和人工智能》是用Amzi Prolog写的,所以建议换本指导教程,比如《Visual Prolog边练边学》,在Visual Prolog官网有下载。

1.编辑器

要说到Windows下可用的编辑器,当仁不让要提到Vim,我很久很久以前曾经用过一阵gVim,但是当初用着是在不惯,加之有Visual Studio这种神器何苦要使Vim?现在,不得不又用回Vim了。

首先到Vim官方主页[6]下载gVim最新版,安装之,Vim自带Prolog的语法高亮模板,你也可以自行替换为别的语法高亮模板,比如Aleksandar Dimitrov的[7]。原始的主题,不是很好看,我一般喜欢黑底的编辑器环境,当然这个看个人喜好,在Vim的网站有多种主题,下载.vim文件后放到…\Vim\vimfiles\colors,然后在编辑-配色方案中选择即可,或者直接输入命令“colo 配色方案名”,比如colo evening,如果想设置为打开时自动设为这个配色方案,需要修改vim目录的_vimrc文件,在最下面加一行colo evening就OK。如果想打开行号,就再加一行,写set nu!。

关于Vim我水平并不高,对Vim有兴趣的童鞋可以再查阅其他相关资料。

不喜欢Vim或者想找一个更轻量级的编辑器的话可以考虑用Notepad++,不过Notepad++原生似乎不支持prolog[8],但是你可以通过自定义语言来实现对Prolog的支持。

clip_image001 Read More →