Prolog 人工智能语言中文论坛---打造优质Prolog学习交流园地

一个供Prolog爱好者学习与交流的地方


您没有登录。 请登录注册

swi-prolog里的foreach与forall谓词有何不同?

浏览上一个主题 浏览下一个主题 向下  留言 [第1页/共1页]

1 swi-prolog里的foreach与forall谓词有何不同? 于 周日 十月 21, 2012 3:02 pm

我看了关于两个谓词的说明,
仍无法体会其差异,
了解的高手说明一下,谢谢!

p.s. 在swi-prolog里查询help(forall).就可以看其说明。

查阅用户资料 http://prolog.longluntan.net
Mercury Liao 写道::我看了关于两个谓词的说明,
仍无法体会其差异,
了解的高手说明一下,谢谢!

p.s. 在swi-prolog里查询help(forall).就可以看其说明。

yauhsien和我写的回贴同时不见了,不晓得遇到什么问题。
我先把刚才为了试验yauhsien写的例子而copy起来的残骸放这,
方便如果yauhsien愿意给我们再写一遍的时候用。

代码:
man('John').
man('Josh').
girl('Betty').
girl('Joan').
father('John', 'Betty').
father('Josh', 'Joan').

9 ?- forall((man(M),write('Test '),write(M),write(': ')),(father(M,_),write('yes. '))).
Test John: yes. Test Josh: yes.
true.

10 ?- foreach((man(M),write('Test '),write(M),write(': ')),(father(M,_),write('yes. '))).
Test John: Test Josh: yes.
false.


查阅用户资料 http://prolog.longluntan.net
我写了一点什麽发送之後,发现没把差别讲得很明白,所以删掉。 Laughing

说foreach(:Generator, :Goal)对Generator找到的每个事实都有一个Goal的复制,并且每个Goal复制都串接起来。後者就是最大的差别,forall/2是对每个事实都做一个动作,foreach/2则是把每个事实的检查合并。

以人际关系看
代码:
man('John') :- write('Take John'),nl.
man('Josh') :- write('Take Josh'),nl.
girl('Betty').
girl('Joan').
father('John', 'Betty') :- write('Test John'),nl.
father('Josh', 'Joan') :- write('Test Josh'),nl.

?- foreach(man(M), father(M,_)).
Take John
Take Josh
Test John
false.
从Generator找到 M='John', M='Josh' ,把Goal复制并串接就是 father('John',_), father('Josh',_) 。如果trace可以看到运行过程是先找到father('John','Betty'),然後检查father('Josh','Betty')得到false。这句的意思是 "找到众人之父" ,这个foreach/2看起来比较接近逻辑学的那个for-all符号。同样一个找爸爸,用forall/2写起来的意思应该是 "找出全部的爸爸" 。

至於forall/2,谓词模板写成forall(:Cond, :Action),它除了提到 "以伪驱使的循环" 之外,提到可以把Action做成有副作用的作法。或许可以用来实现C语言的for循环,例如2x1~3x9乘法表,
代码:

?- forall((between(2,3,X),between(1,9,Y)),
          (write(X),write('*'),write(Y),write('='),N is X*Y,write(N),nl)).

查阅用户资料 http://yauhsien.wordpress.com
yauhsien 写道::我写了一点什麽发送之後,发现没把差别讲得很明白,所以删掉。 Laughing

说foreach(:Generator, :Goal)对Generator找到的每个事实都有一个Goal的复制,并且每个Goal复制都串接起来。後者就是最大的差别,forall/2是对每个事实都做一个动作,foreach/2则是把每个事实的检查合并。

以人际关系看
代码:
man('John') :- write('Take John'),nl.
man('Josh') :- write('Take Josh'),nl.
girl('Betty').
girl('Joan').
father('John', 'Betty') :- write('Test John'),nl.
father('Josh', 'Joan') :- write('Test Josh'),nl.

?- foreach(man(M), father(M,_)).
Take John
Take Josh
Test John
false.
从Generator找到 M='John', M='Josh' ,把Goal复制并串接就是 father('John',_), father('Josh',_) 。如果trace可以看到运行过程是先找到father('John','Betty'),然後检查father('Josh','Betty')得到false。这句的意思是 "找到众人之父" ,这个foreach/2看起来比较接近逻辑学的那个for-all符号。同样一个找爸爸,用forall/2写起来的意思应该是 "找出全部的爸爸" 。

至於forall/2,谓词模板写成forall(:Cond, :Action),它除了提到 "以伪驱使的循环" 之外,提到可以把Action做成有副作用的作法。或许可以用来实现C语言的for循环,例如2x1~3x9乘法表,
代码:

?- forall((between(2,3,X),between(1,9,Y)),
          (write(X),write('*'),write(Y),write('='),N is X*Y,write(N),nl)).

看明白了,讲得非常清楚,感谢!


有3点想说的:

1. 我觉得它的名字好像取反了,比起foreach/2它的forall/2更像是英文语意上的"for each",
each在语意上有"独立地"、"分别地"的意思,
而forall/2可以让每个Action"分别单独地"执行(并不联合起来检查正确性),应取作foreach较合理;
而foreach/2,在检查Goal时是联合起来检查,已经没有"分别地"的感觉,反而更像是"for all"(意思是:对所有皆必须成立)。

2. 如果在forall的查询里增加一句"X = 2",那会变成:

23 ?- forall((between(2,3,X),between(1,9,Y)), (write(X),write('*'),write(Y),write('='),N is X*Y, X = 2, write(N),nl)).
2*1=2
2*2=4
2*3=6
2*4=8
2*5=10
2*6=12
2*7=14
2*8=16
2*9=18
3*1=
false.

这里感觉有点奇怪,因为手册上说forall/2是failure driven loop(以失败为手段强制驱动它循环的),
既然是这样,应该也要印出"3*2="、"3*3="、"3*4="……"3*9=",
但从结果来看,它印到"3*1=",然后检查了一下"X=2"为false,后面就全部不执行了,
跟我想的failure driven loop执行结果有差异啊!不知道为什么。

3. 嗯,forall/2看来是能模拟简单的for循环,但还是不具备传回静态变量的功能。

查阅用户资料 http://prolog.longluntan.net

浏览上一个主题 浏览下一个主题 返回页首  留言 [第1页/共1页]

您在这个论坛的权限:
不能在这个论坛回复主题