`

Logic Programming With Prolog学习笔记(二)

阅读更多

 

第六章:循环

1、一定次数的循环,看代码,与 Erlang 一模一样:

loop(0).

loop(N):-N>0,write('The value is: '),write(N),nl,

M is N-1,loop(M).

再看一个例子:

output_values(Last,Last):- write(Last),nl,

write('end of example'),nl.

output_values(First,Last):-First=\=Last,write(First),

nl,N is First+1,output_values(N,Last).

2、循环直到条件满足:

go:-loop(start).

loop(end).

loop(X):-X\=end,write('Type end to end'),read(Word),

write('Input was '),write(Word),nl,loop(Word).

通过 ;/2谓词,可以改写为:

loop:-write('Type end to end'),read(Word),

write('Input was '),write(Word),nl,

(Word=end;loop).


3 、使用 repeat 谓词,这个谓词名称是典型的用词不当, repeat 并不重复任何东西,它仅仅是在任何时候执行的时候都是 success 。那么当回溯到 repeat 的时候,因为它是成功的,那么就要继续从 left->right 的求值目标,直到后续的某个目标满足为止,例如:

get_answer(Ans):-

write('Enter answer to question'),nl,

repeat,write('answer yes or no'),read(Ans),

valid(Ans),write('Answer is '),write(Ans),nl.

valid(yes). valid(no).

这个程序检测输入,要求玩家必须输入 yes 或者 no 才算结束,在 repeat valid(Ans) 之间,如果没有输入 yes 或者 no ,将循环多次,直到 valid(Ans) 目标被满足(也就是输入 yes 或者 no )。回溯到 repeat 的时候,总是成功,那么就继续求值后续的目标 write('answer yes or no'),read(Ans),repeat 左边的部分永远不会被回溯到。


4 fail 谓词 ,fail 谓词求值总是 fail ,因此强迫回溯开始,例如下面的例子:

dog(fido).

dog(fred).

dog(jonathan).

all_dogs:-

dog(X),write(X),write(' is a dog'),nl,fail.

all_dogs.


谓词 all_dogs 用于查询数据库中所有的 dog ,注意,最后的 all_dogs. 必须存在,不然 all_dogs. 在查找完所有的 dog 之后将总是 fail


第六章:预防回溯

1 cut 谓词:用于中止回溯,也可用!号表示。例如下面的例子:

classify(0,zero).
classify(N,negative):-N<0.
classify(N,positive).


用于检验某个数是正、负或者零。执行:

classify(-4,X).
X = negative ;
X = positive

由于不能中止回溯,当 classify(N,negative):-N<0.执行后,后续的也将执行,当然,你可以修改为:

classify(0,zero).
classify(N,negative):-N<0.
classify(N,positive):-N>0.

如果用cut谓词更好:

classify(0,zero):-!.
classify(N,negative):-N<0,!.
classify(N,positive).

尽管一些程序可以不通过cut谓词进行修改,但是有一些程序(特别是当一个谓词调用另一个谓词的时候)却是不得不借住cut谓词来中止回溯,才能实现正确的行为。

cut的另一个用途就是确定通常情况下以外的异常,与fail搭配使用,我们知道fail强迫回溯开始

例如有以下事实:

bird(sparrow).
bird(eagle).
bird(duck).
bird(crow).
bird(ostrich).
bird(puffin).
bird(swan).
bird(albatross).
bird(starling).
bird(owl).
bird(kingfisher).
bird(thrush).



假设ostrich不能fly,我们的can_fly谓词可能实现为:

can_fly(ostrich):-fail.
can_fly(X):-bird(X).

但是由于fail强制回溯,那么can_fly(ostrich).还是成功,怎么办呢?用cut:

can_fly(ostrich):-!,fail.
can_fly(X):-bird(X).

cut中止了回溯。



第8章:改变Prolog数据库

1、改变数据库:加入和删除语句

如果删除和加入语句仅仅靠consult和reconsult谓词是低效,因此Prolog提供了BIPs用于删除或者增加数据库中的语句。

如果一个谓词可以被assertz, retract等BIPs修改,那么它必须声明是动态的,否则Prolog将报错。动态声明必须放在谓词声明的前面,最好放在整个程序的前面,声明方式如下:

dynamic(mypred/3).

这就将mypred/3谓词声明为动态,可用BIPs进行增删了。

1)增加语句,通过谓词assertz/1和asserta/1,两者的区别在于:前者将语句加入相应谓词的后面,而后者将语句加入相应谓词的开始处。例如:

?-assertz(dog(fido)).
?-assertz((go:-write('hello world'),nl)).

?-assertz(dog(X)).
?-assertz((go(X):-write('hello '),write(X),nl)).



2) 删除语句,也有两个谓词:retract/1和retractall/1,两者的区别在于:前者接受一个参数,并且是一条语句,删除数据库中第一条与该语 句匹配的语句;后者仅接受语句的head部分,用于删除所有的满足该head的语句。例如,假设数据库中有如下语句:

dog(jim).
dog(fido).
dog(X).

执行

?-retract(dog(fido)).

删除数据库中的第2条语句,执行

?-retract(dog(X)).

却是删除dog(jim).因为这是第一条与(dog(X)匹配的语句,而最后的dog(X).反而得到保留。



retractall(mypred(_,_,_)).删除所有的mypred/3谓词语句。

retractall(parent(john,Y)).删除所有的第一个参数的john的parent/2语句。

retractall(mypred).删除所有的mypred/0谓词。


2、维护事实库,利用文件读写IO谓词,和本章介绍的增删谓词,就用文本文件维护事实库了,具体例子不说了。



第9章:列表处理

1、list在Prolog中是以[]包括的,以,号隔开的term组成,例如[a,b,c,d],空列表就是[]。了解过Erlang或者scheme的朋友,应该对列表很熟悉。Erlang中的列表与Prolog中的列表概念一脉相承。

2、这一章,真没啥好细谈的,列几个BIPs吧

1)member,判断元素是否在列表中

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

?- member(mypred(a,b,c),[q,r,s,mypred(a,b,c),w]).

yes

如果member的第一个参数是未绑定的变量,那么该变量将从左到右依次绑定列表中的元素。

2)length谓词,确定列表长度,第2个参数如果是变量,将变量绑定为列表参数,如果是数字,就将该数字与长度比较,相等则success,否则fail。

?- length([a,b,c,d],X).
X = 4

?- length([a,b,c],3).
yes

?- length([a,b,c],4).
no

3)reverse谓词,如果两个变量都是list,就判断是否互相倒序,如果一个是变量,一个是list,就将变量绑定为list的倒序:

?- reverse([1,2,3,4],L).
L = [4,3,2,1]
?- reverse(L,[1,2,3,4]).
L = [4,3,2,1]

?- reverse([1,2,3,4],[4,3,2,1]).
yes

4)append谓词,三个参数,如果前两个是list,第三个为变量,那么将变量绑定为两个list合并连接的列表:

?- append([1,2,3,4],[5,6,7,8,9],L).
L = [1,2,3,4,5,6,7,8,9]
?- append([],[1,2,3],L).
L = [1,2,3]


如果前两个参数包括变量,第三个是列表,那么将回溯寻找所有可能的列表组合:

?- append(L1,L2,[1,2,3,4,5]).
L1 = [] ,
L2 = [1,2,3,4,5] ;
L1 = [1] ,
L2 = [2,3,4,5] ;
L1 = [1,2] ,
L2 = [3,4,5] ;
L1 = [1,2,3] ,
L2 = [4,5] ;
L1 = [1,2,3,4] ,
L2 = [5] ;
L1 = [1,2,3,4,5] ,
L2 =[] ;

no


5) findall/3谓词比较有趣,有点类似select的概念,它有三个参数,第一个参数是一个变量或者带变量的表达式,用于确定想要find并且 collect的元素结构,第二个参数是一个goal,用于执行数据库中是否有匹配项,第三个参数是变量,用于绑定最后收集到的匹配的元素列表,例子:

假设我们已经如下事实:

person(john,smith,45,london).
person(mary,jones,28,edinburgh).
person(michael,wilson,62,bristol).
person(mark,smith,37,cardiff).
person(henry,roberts,23,london).



那么执行:

findall(S,person(_,S,_,_),L).

将返回:

L = [smith,jones,wilson,smith,roberts]

L收集了所有person的姓。如果执行:

?- findall([Forename,Surname],person(Forename,Surname,_,_),L).


将返回所有person的姓名组成的列表的列表:

L = [[john,smith],[mary,jones],[michael,wilson],[mark,smith],[henry,roberts]]


这是个非常有用的谓词。



第10章:字符串处理

1、单引号括起来的atom就是字符串,又一个Erlang沿用Prolog的典型,字符串本质上就是anscii码组成的列表,列表跟字符串可以互相转化,通过name/2谓词:

?- name('Prolog Example',L).
L = [80,114,111,108,111,103,32,69,120,97,109,112,108,101]

?-name(A,[80,114,111,108,111,103,32,69,120,97,109,112,108,101]).
A = 'Prolog Example'


2、常用谓词,一般的Prolog系统其实都有字符串扩展谓词,这里提供基本的实现:

1)连接字符串:

join2(String1,String2,Newstring):-
   name(String1,L1),name(String2,L2),
   append(L1,L2,Newlist),
   name(Newstring,Newlist).

转成列表,通过append连接成新的列表,再转成字符串。

2)Trim谓词,去除前后空格字符:

trim([A|L],L1):-A=<32,trim(L,L1).
trim([A|L],[A|L]):-A>32.

trim2(L,L1):-
reverse(L,Lrev),trim(Lrev,L2),reverse(L2,L1).

trim3(L,L1):-trim(L,L2),trim2(L2,L1).
trims(S,Snew):-name(S,L),trim3(L,L1),name(Snew,L1).

真是麻烦呐,与join2是同样的套路。

3)读入一行的readline谓词:

readline(S):-readline1([],L),name(S,L),!.
readline1(Oldlist,L):-get0(X),process(Oldlist,X,L).
process(Oldlist,13,Oldlist).
process(Oldlist,X,L):-
  append(Oldlist,[X],L1),readline1(L1,L).



第11章:高级特性


1、操作符的扩展,通过op/3谓词(略)

2、term的处理,比较有趣的=..操作符,例如:

X=..[member,A,L].

将X绑定为member(A,L).

X=..[colour,red].

X绑定为color(red),=..称为univ操作符(摘要操作符?),用于列表和term之间的相互转化,反过来:

?- data(6,green,mypred(26,blue))=..L.

L将绑定为

L = [data,6,green,mypred(26,blue)]



3、call/1谓词,接受一个call term参数,类似目标执行,例如:

call(write('Hello world')).

输出:

Hello worldyes


可执行多个term:

?-call(write('Hello world'),nl).

Hello world

yes


call跟=..联合调用:

?- X=..[write,'hello world'],call(X).
hello worldX = write('hello world')



4、functor/3谓词:当第一个参数是atom或者compound term或者某个绑定了类似值的变量,第二和第三个参数是未绑定变量,那么第二个参数变量将绑定为第一个参数的functor,第三个参数变量绑定为第一个参素的arity,举例子说明:

?- functor(write('hello world'),A,B).
A = write ,
B = 1

?- functor(start,F,A).
F = start ,
A = 0

?- functor(a+b,F,A).
F = + ,
A = 2

显然,atom的arity是0。反过来,如果第一个参数是未绑定变量,后两个参数已知:

?- functor(T,person,4).
T = person(_42952,_42954,_42956,_42958)
?- functor(T,start,0).
T = start


5、arg/3谓词,根据第一个参数数值,取第二个参数term的相应位置的参数,例如:

?- arg(3,person(mary,jones,doctor,london),X).
X = doctor

X绑定为person(mary,jones,doctor,london)的第3个参数。

分享到:
评论

相关推荐

    An Introduction to Logic Programming through Prolog

    标题“An Introduction to Logic Programming through Prolog”直译为“通过Prolog介绍逻辑程序设计”,表明了本文旨在通过Prolog语言来介绍逻辑编程的基础知识。Prolog是一种逻辑编程语言,广泛应用于人工智能领域...

    prolog.rar_logic programming_prolog_prolog intelligence_人工智能_人工智

    prolog语言教程,一种非常适合于人工智能编程的逻辑语言

    Programming in Prolog, 5th ed (2003).pdf

    Prolog(Programming in Logic的缩写)是一种高级编程语言,主要用于人工智能研究和开发。它由逻辑推理机制来驱动,让程序员能够编写程序,这些程序更接近自然语言的表达,可以用来解决诸如自然语言处理、专家系统和...

    Logic_Programming_with_Prolog

    Prolog(Programming in Logic)的名字直观地反映了其本质,即在逻辑中进行编程。该语言基于20世纪60年代和70年代欧洲计算机科学家的研究成果,尤其是在法国马赛大学、英国伦敦和爱丁堡等地的研究工作基础上发展而来...

    通过Prolog进行逻辑编程的简介An Introduction to Logic Programming Through Prolog

    介绍逻辑编程,将三个基本组成部分组合在一起:逻辑本身的声明性,编写有效程序所需的编程技术以及计算机对逻辑编程的有效实现。

    Logic.Programming.In.Prolog.Using.The.ISO.Standard

    **标题**:“Logic.Programming.In.Prolog.Using.The.ISO.Standard”(逻辑编程在Prolog中的应用:基于ISO标准) **描述**:“Logic.Programming.In.Prolog.Using.The.ISO.Standard”(逻辑编程在Prolog中的应用:...

    Programming in Prolog

    #### 二、Prolog的发展历程与标准化 自前一版本发布以来,Prolog语言已经实现了国际化标准(ISO标准),这标志着Prolog语言在国际上的认可度和影响力显著提升。ISO标准化不仅提高了Prolog的可移植性,也促进了该...

    Logic.Programming.with.Prolog

    《使用Prolog进行逻辑编程》一书由Max Bramer撰写,深入探讨了逻辑编程这一独特且与传统编程语言如C++和Java截然不同的编程风格。逻辑编程的核心理念在于其清晰、简洁,以及通常被认为更优越的特性。本书通过Prolog...

    Latest Advances in Inductive Logic Programming

    标题与描述均指出本资料关注的是“最新进展在归纳逻辑编程(Inductive Logic Programming, ILP)”这一领域。归纳逻辑编程是一种机器学习技术,它结合了逻辑编程与机器学习的概念,用于推导出适用于特定数据集的逻辑...

    prolog 学习资料 英文 附示例

    4. **《Logic Programming with Prolog》** - 这本书由M. Bramer撰写,Springer出版社于2005年出版,深入介绍了Prolog编程语言。 - 可能涵盖Prolog语法、控制结构、递归、模式匹配、数据结构、程序调试等内容。 -...

    .Net Prolog 扩展

    Logic programming for .NET Prolog.NET is a full featured Prolog programming environment for the .NET Framework. It includes an enhanced compiler with language extensions and a code generator targeting...

    Inductive Logic Programming_ Techniques and Applications

    标题《Inductive Logic Programming Techniques and Applications》表明本书是关于归纳逻辑编程(Inductive Logic Programming,简称ILP)的技术和应用的。ILP是一种机器学习方法,它结合了逻辑编程和归纳学习的技术...

    逻辑,编程和序言,第二版Logic, Programming and Prolog, Second Edition

    介绍并发,方程式和约束逻辑编程等主题。 在对理论进行清晰,权威的处理与实际应用中解决问题的方法之间取得平衡。

    prolog programming for artificial intelligence

    Prolog(Programming in Logic)是一种高级编程语言,特别适合于符号处理、知识表示和逻辑推理。它广泛应用于人工智能领域,特别是在专家系统和自然语言处理等方面。 为了满足要求,我将从Prolog和人工智能这两个...

    通过Prolog介绍逻辑编程

    Chapters 9 to 13 present more practical topics, from the formulation of graph-searching problems so that they can be solved by Prolog’s simple search strategy, to applications of logic programming in...

    prolog.rar_pdf_programming_prolog_software

    Prolog.pdf pages 294.

    序言和逻辑程序设计Prolog and Logic Programming

    逻辑编程简介。 本课程从Prolog开始,因为据信,如果读者对它与理论的实际实例有何联系,则可以更轻松地学习该理论。

Global site tag (gtag.js) - Google Analytics