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

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


您没有登录。 请登录注册

如何用prolog编写程序来解答4证人难题?

到页面 : 1, 2  下一步

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

1 如何用prolog编写程序来解答4证人难题? 于 周一 三月 26, 2012 2:11 am

调查了罪案的4位证人。从证人的话侦探得出的结论是:
如果男管家(mate)说的是真话,那么厨师(cook)说的也是真话。
厨师和园丁(gardener)说的不可能都是真话。
园丁和杂役(worker)说的不可能都是谎话。
如果杂役说真话,那么厨师在撒谎。请问,侦探能分别出这4位证人谁在说真话谁在撒谎吗?
*******************************************************
我想用prolog来写出程序进行推理,感觉到困难的地方是:
(1)"厨师和园丁(gardener)说的不可能都是真话"这样的逻辑用prolog该怎么表示呢?
(2)能否写出一个简单的程序来推出结论?
(3)假设推理的结果是要么A说真话要么B说真话,但是不可能同时说真话。这样的结论prolog以什么样的形式表示呢? 例如我的prolog程序的字句叫做true()。那么当我输入完条件的时候,请求结论true(X).的时候,prolog打印结果是打印可能的X。但是我刚才说了,如果答案是一个"异或"的答案,prolog该怎么打印结果呢?


查阅用户资料
kgisme169 写道::调查了罪案的4位证人。从证人的话侦探得出的结论是:
如果男管家(mate)说的是真话,那么厨师(cook)说的也是真话。
厨师和园丁(gardener)说的不可能都是真话。
园丁和杂役(worker)说的不可能都是谎话。
如果杂役说真话,那么厨师在撒谎。请问,侦探能分别出这4位证人谁在说真话谁在撒谎吗?
*******************************************************
我想用prolog来写出程序进行推理,感觉到困难的地方是:
(1)"厨师和园丁(gardener)说的不可能都是真话"这样的逻辑用prolog该怎么表示呢?
(2)能否写出一个简单的程序来推出结论?
(3)假设推理的结果是要么A说真话要么B说真话,但是不可能同时说真话。这样的结论prolog以什么样的形式表示呢? 例如我的prolog程序的字句叫做true()。那么当我输入完条件的时候,请求结论true(X).的时候,prolog打印结果是打印可能的X。但是我刚才说了,如果答案是一个"异或"的答案,prolog该怎么打印结果呢?





以下的程序码应该足够能回答你上面所有的问题:

代码:
possible_solution(Solution) :- length(Solution,4), maplist(form_condition,Solution).
form_condition(X) :- member(X,[istrue,isfalse]).

condition1([M,C,G,W]) :- M = istrue, C = istrue; M = isfalse.
condition2([M,C,G,W]) :- not((C = istrue, G = istrue)).
condition3([M,C,G,W]) :- not((G = isfalse, W = isfalse)).
condition4([M,C,G,W]) :- W = istrue, C = isfalse; W = isfalse.



question :-
  possible_solution(Solution), condition1(Solution), condition2(Solution), condition3(Solution), condition4(Solution),
  Solution = [M,C,G,W], write(mate-M), write(', '),write(cook-C), write(', '),write(gardener-G), write(', '),write(Worker-W), nl.

执行 ?-question.后,得到:
mate-isfalse, cook-isfalse, gardener-istrue, worker-istrue
mate-isfalse, cook-isfalse, gardener-istrue, worker-isfalse
mate-isfalse, cook-isfalse, gardener-isfalse, worker-istrue

也就是说,管家和廚师肯定是说谎的,园丁和杂役2个人至少有一个说实话。



由Mercury Liao于周一 三月 26, 2012 12:30 pm进行了最后一次编辑,总共编辑了2次

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

代码:

mate(true).
mate(false).
cook(true).
cook(false).
gardener(true).
gardener(false).
worker(true).
worker(false).

solve(Mate, Cook, Gardener, Worker) :-
mate(Mate), cook(Cook), (Mate == true -> Cook == true; true),
gardener(Gardener), (Cook \= Gardener; Cook == false, Gardener == false),
worker(Worker), (Worker \= Gardener; Worker == true, Gardener == true),
(Worker == true -> Cook == false; true).

运行结果:有三个解
| ?- solve(M,C,G,W).
C = false,
G = true,
M = false,
W = true ? ;

C = false,
G = true,
M = false,
W = false ? ;

C = false,
G = false,
M = false,
W = true ? ;

查阅用户资料
这句话没有看懂:

(Mate == true -> Cook == true; true),

->推出后面为什么要加一个分号,分号后面又加个true是什么含义,为什么结尾的地方要有个true?

查阅用户资料
kgisme169 写道::这句话没有看懂:

(Mate == true -> Cook == true; true),

->推出后面为什么要加一个分号,分号后面又加个true是什么含义,为什么结尾的地方要有个true?


"-> ;"是if...else的句型,用法是"if true -> then ; else",
举例来说,假如有
A -> B ; C.
那么A为真时执行B,A为假时执行C,
整个句子的对错决定于B和C,也就是说,即使A为错,只要C是对的,
整个句子还是对的。

他这么写的目的其实就是:
若Mate == true,则Cook == true;
但,如果 Mate == true不成立,我仍然希望这个句子是成功的,
因此在分号后面得加上一个true,表示不用做任何事,我单纯只是想让这个句子成功。

查阅用户资料 http://prolog.longluntan.net
Mercury Liao 写道::
kgisme169 写道::这句话没有看懂:

(Mate == true -> Cook == true; true),

->推出后面为什么要加一个分号,分号后面又加个true是什么含义,为什么结尾的地方要有个true?


"-> ;"是if...else的句型,用法是"if true -> then ; else",
举例来说,假如有
A -> B ; C.
那么A为真时执行B,A为假时执行C,
整个句子的对错决定于B和C,也就是说,即使A为错,只要C是对的,
整个句子还是对的。

他这么写的目的其实就是:
若Mate == true,则Cook == true;
但,如果 Mate == true不成立,我仍然希望这个句子是成功的,
因此在分号后面得加上一个true,表示不用做任何事,我单纯只是想让这个句子成功。

如果我单纯就写一个(Mate == true -> Cook == true)
这样会有什么问题么? 因为我只是想表达,如果管家说的是真话,那么厨师说的也是真话。
你的意思是说,如果管家说的不是真话,这句话也要为true。可是(Mate == false->true)这有什么意义么?

如果没有后面添加的这个true,会有什么逻辑上的不同么? 我还是没有理解。

查阅用户资料
kgisme169 写道::
Mercury Liao 写道::
kgisme169 写道::这句话没有看懂:

(Mate == true -> Cook == true; true),

->推出后面为什么要加一个分号,分号后面又加个true是什么含义,为什么结尾的地方要有个true?


"-> ;"是if...else的句型,用法是"if true -> then ; else",
举例来说,假如有
A -> B ; C.
那么A为真时执行B,A为假时执行C,
整个句子的对错决定于B和C,也就是说,即使A为错,只要C是对的,
整个句子还是对的。

他这么写的目的其实就是:
若Mate == true,则Cook == true;
但,如果 Mate == true不成立,我仍然希望这个句子是成功的,
因此在分号后面得加上一个true,表示不用做任何事,我单纯只是想让这个句子成功。

如果我单纯就写一个(Mate == true -> Cook == true)
这样会有什么问题么? 因为我只是想表达,如果管家说的是真话,那么厨师说的也是真话。
你的意思是说,如果管家说的不是真话,这句话也要为true。可是(Mate == false->true)这有什么意义么?

如果没有后面添加的这个true,会有什么逻辑上的不同么? 我还是没有理解。

这是出于流程上的原因。
就拿这个solve谓词来说明吧,
假设
solve :- A, B, C, D, E.
也就是说我们希望透过执行A,B,C,D,E的判断来产生解答对不?
Prolog在运行时,","是当And来理解的,
"A,B"意即当A与B都为真时才为真,
如果A为假,Prolog就不会判断B,
原因很简单,A为假,(A,B)肯定为假,不需要判断B就可得知。

现在你可以把Mate == false看成是A,
如果A为假,Prolog会中断solve的执行并返回false,
这并不是我们希望的,我们希望的是它继续执行后面的B、C、D、E,
在这个例子也就是执行
gardener(Gardener), (Cook \= Gardener; Cook == false, Gardener == false)......等。

总之,Prolog是把Solve当逻辑题来做,但我们对这道题的真假一点都不在乎,
我们是把solve当一个命令集来用,
就是告诉Prolog说,你给我做完solve后面的所有命令就对了,
(然后返回相应的值true/false到solve的4个参数以表示这4个人说谎话还是说实话),
当然了,中间穿插了些if...else判断语句,跳过某些我们不想要执行的句子。



由Mercury Liao于周二 三月 27, 2012 4:27 am进行了最后一次编辑,总共编辑了1次

查阅用户资料 http://prolog.longluntan.net
根据Prolog语言标准,+P -> +Q 相当于 (P -> Q; fail),因此后面那个; true不可省略

查阅用户资料
wdx04 写道::根据Prolog语言标准,+P -> +Q 相当于 (P -> Q; fail),因此后面那个; true不可省略

你的意思是不是说: 有了这个true判断,整个solve的过程才能进行下去。否则false的时候,就会停在那里fail掉了?

查阅用户资料
kgisme169 写道::
wdx04 写道::根据Prolog语言标准,+P -> +Q 相当于 (P -> Q; fail),因此后面那个; true不可省略

你的意思是不是说: 有了这个true判断,整个solve的过程才能进行下去。否则false的时候,就会停在那里fail掉了?

是的,我前一篇回复你的留言里写的也是这个意思,你可以再看看。

查阅用户资料 http://prolog.longluntan.net
Mercury Liao 写道::
kgisme169 写道::
wdx04 写道::根据Prolog语言标准,+P -> +Q 相当于 (P -> Q; fail),因此后面那个; true不可省略

你的意思是不是说: 有了这个true判断,整个solve的过程才能进行下去。否则false的时候,就会停在那里fail掉了?

是的,我前一篇回复你的留言里写的也是这个意思,你可以再看看。

请教solve函数的用法:
solve(Mate, Cook, Gardener, Worker)是不是会把solve当中的4个参数,穷举其true/false的各种可能性组合?

我这样的理解对么?

查阅用户资料
donet8 写道::
Mercury Liao 写道::
kgisme169 写道::
wdx04 写道::根据Prolog语言标准,+P -> +Q 相当于 (P -> Q; fail),因此后面那个; true不可省略

你的意思是不是说: 有了这个true判断,整个solve的过程才能进行下去。否则false的时候,就会停在那里fail掉了?

是的,我前一篇回复你的留言里写的也是这个意思,你可以再看看。

请教solve函数的用法:
solve(Mate, Cook, Gardener, Worker)是不是会把solve当中的4个参数,穷举其true/false的各种可能性组合?

我这样的理解对么?

会为这4个参数找出符合":-"右边的规则的所有可能。
如果你是这么理解的,你说的就没错。

查阅用户资料 http://prolog.longluntan.net
这里的true和false是不是prolog的关键字,就像C语言里面的关键字一样?

还是说,对于prolog而言,这只是一个字符串的取值而已,prolog并不去试图了解true和false的意义?

查阅用户资料
donet8 写道::这里的true和false是不是prolog的关键字,就像C语言里面的关键字一样?

还是说,对于prolog而言,这只是一个字符串的取值而已,prolog并不去试图了解true和false的意义?


这里的ture/false是给人看的,代表说实话或说谎话,
对prolog用来判断事情没有任何差别,你换成aaaa/bbbbb也可以,
只要你自己知道aaaa、bbbbb哪个代表说实话哪个代表说谎话就可以。

不过true、false这两个字也是prolog的关键字,
表示一个规则或解为真,或是无法证明为真,
只是在这个例子里,true/false不是当关键字来用的。

查阅用户资料 http://prolog.longluntan.net
那么,你之前说的:"因此在分号后面得加上一个true,表示不用做任何事,我单纯只是想让这个句子成功。"

这里的true 是prolog的关键字么?

查阅用户资料
donet8 写道::那么,你之前说的:"因此在分号后面得加上一个true,表示不用做任何事,我单纯只是想让这个句子成功。"

这里的true 是prolog的关键字么?

是关键字,代表程序继续执行solve,
而类似像mate(true), cook(false)这种的不是关键字,
这种你换成mate(hahaha), cook(wuwuwu)一样可以,
只要自己知道hahaha、wuwuwu什么意思就行。

查阅用户资料 http://prolog.longluntan.net
donet8 写道::那么,你之前说的:"因此在分号后面得加上一个true,表示不用做任何事,我单纯只是想让这个句子成功。"

这里的true 是prolog的关键字么?
求回答!

查阅用户资料
donet8 写道::那么,你之前说的:"因此在分号后面得加上一个true,表示不用做任何事,我单纯只是想让这个句子成功。"

这里的true 是prolog的关键字么?

是的。
基本上只有XXX(true), YYY(false)这种不是。

查阅用户资料 http://prolog.longluntan.net
[quote="Mercury Liao"]

不好意思,我是菜鸟。刚刚才发现每个情况后面要打一个;
才会出现第2中情况。

但我想问一下,为什么每次要打一个分号呢?而且最后3种情况都出现后,再打一个分号返回false是为什么?

问题很小白。。。谢谢!

查阅用户资料
Mercury Liao 写道::
donet8 写道::那么,你之前说的:"因此在分号后面得加上一个true,表示不用做任何事,我单纯只是想让这个句子成功。"

这里的true 是prolog的关键字么?

是关键字,代表程序继续执行solve,
而类似像mate(true), cook(false)这种的不是关键字,
这种你换成mate(hahaha), cook(wuwuwu)一样可以,
只要自己知道hahaha、wuwuwu什么意思就行。

这里我不太懂,程序最开始的
mate(true).
mate(false).
cook(true).
cook(false).
...
这到底是在列举事实fact,还是可能性possiblity?

另外solve(A,B,C,D,E)里面的A--E是variable变量,还是term项?
如果是变量,那最后就是将变量实例化是吗?

谢谢!

查阅用户资料
[quote="ccandkk"]
Mercury Liao 写道::

不好意思,我是菜鸟。刚刚才发现每个情况后面要打一个;
才会出现第2中情况。

但我想问一下,为什么每次要打一个分号呢?而且最后3种情况都出现后,再打一个分号返回false是为什么?

问题很小白。。。谢谢!

prolog会先找出满足你查询的一组解答,然后等待你的指示,
如果你按";"表示你还想知道有无其他解答,
不按的话它就当你只需一个解答就够了,不再回溯。

最后返回一个false,表示prolog无论根据哪个事实,
都无法再证明你的查询为真,prolog就当false处理。
所以在prolog里,false其实应该解释为"无法(没有足够证据)证明其为真"。

查阅用户资料 http://prolog.longluntan.net
ccandkk 写道::
Mercury Liao 写道::
donet8 写道::那么,你之前说的:"因此在分号后面得加上一个true,表示不用做任何事,我单纯只是想让这个句子成功。"

这里的true 是prolog的关键字么?

是关键字,代表程序继续执行solve,
而类似像mate(true), cook(false)这种的不是关键字,
这种你换成mate(hahaha), cook(wuwuwu)一样可以,
只要自己知道hahaha、wuwuwu什么意思就行。

这里我不太懂,程序最开始的
mate(true).
mate(false).
cook(true).
cook(false).
...
这到底是在列举事实fact,还是可能性possiblity?

另外solve(A,B,C,D,E)里面的A--E是variable变量,还是term项?
如果是变量,那最后就是将变量实例化是吗?

谢谢!

意义上是"可能性",不过单看每一句,在prolog里都称为事实,
在这里,mate(true)是一种可能的事实,mate(false)又是一种可能的事实……
全部把可能的事实列出来,让prolog一个一个匹配,
比如它先将mate(true)当做真,然后执行啊执行,可能会导出矛盾的结果,
然后prolog会考虑其他事实,也就是再将mate(false)当做真,执行啊执行,看看能否满足你的查询。

A--E都是大写字母开头,当然是变量了(term项必须是小写字母开头,或是用''引起来),
而且A--E是未绑定的变量,也就是说A--E一开始都是空的,里面没有实际的值,
(可以理解为NULL吧如果是在其他语言里的用词),
透过不断的匹配尝试,最后找出可能的A--E,也就是你说的实例化。

查阅用户资料 http://prolog.longluntan.net
[quote="Mercury Liao"]

非常感谢版主的解释!很详细也很清楚。

但我对这2句不大懂:
mate(Mate), cook(Cook), (Mate == true -> Cook == true; true)如果这句是判断【如果男管家(mate)说的是真话,那么厨师(cook)说的也是真话。】
为什么前面要加上 mate(Mate), cook(Cook), 这2句?


而(Worker == true -> Cook == false; true).是判断【如果杂役说真话,那么厨师在撒谎。】为什么前面不用加 worker(Worker)呢?


非常感谢

查阅用户资料
[quote="ccandkk"]
Mercury Liao 写道::

非常感谢版主的解释!很详细也很清楚。

但我对这2句不大懂:
mate(Mate), cook(Cook), (Mate == true -> Cook == true; true)如果这句是判断【如果男管家(mate)说的是真话,那么厨师(cook)说的也是真话。】
为什么前面要加上 mate(Mate), cook(Cook), 这2句?


而(Worker == true -> Cook == false; true).是判断【如果杂役说真话,那么厨师在撒谎。】为什么前面不用加 worker(Worker)呢?


非常感谢


因为Mate和Cook都还没有实例化,
判断Mate == true的话一定是false,没有意义。
而先执行mate(Mate), cook(Cook),
可以将Mate与Cook实例化为true ture、true false、false true、false false四种的任一种,
后面再判断符不符合所设定的条件。

至于worker(Worker)我看他有加啊!还是我看错了?
你再确定一下哈。

查阅用户资料 http://prolog.longluntan.net
非常感谢版主!!那么晚了还回复我。这个prolog的很多题目和以前学的离散数学好像啊。不过跟C语言什么的区别还是挺大的。这学期刚刚接触!

再次感谢! Very Happy

查阅用户资料

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

到页面 : 1, 2  下一步

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