gprolog新手-如何让这个简短的程序得出正确的结论?
我有以下gprolog程序:gprolog新手-如何让这个简短的程序得出正确的结论?,prolog,logic,Prolog,Logic,我有以下gprolog程序: father(charles, harry). daughter(elizabeth, george). son(william, charles). father(X, Y) :- son(Y, X). father(X, Y) :- daughter(Y, X). daughter(X, Y) :- \+son(X, Y), father(Y, X). son(X, Y) :- \+daughter(X, Y), father(Y, X). 鉴于我的情况,
father(charles, harry).
daughter(elizabeth, george).
son(william, charles).
father(X, Y) :- son(Y, X).
father(X, Y) :- daughter(Y, X).
daughter(X, Y) :- \+son(X, Y), father(Y, X).
son(X, Y) :- \+daughter(X, Y), father(Y, X).
鉴于我的情况,我尝试了以下查询:
| ?- son(harry, charles).
…并得到了一个不
(也就是说,据我所知,“Prolog无法证明这一点。”)。当我对它进行跟踪时,它似乎没有太大帮助:
{trace}
| ?- son(harry, charles).
1 1 Call: son(harry,charles) ?
1 1 Fail: son(harry,charles) ?
由于儿子(哈里,查尔斯)应该匹配到我代码的最后一行,我想程序只需检查第一部分:\+女儿(X,Y)
(“Prolog无法证明哈里是查尔斯的女儿”,对吧?)。事实上:
那么它将进入第二部分,对吗?它将检查父亲(Y,X)
,即父亲(查尔斯,哈里)
,这是事实
| ?- father(charles, harry).
1 1 Call: father(charles,harry) ?
1 1 Exit: father(charles,harry) ?
(1 ms) yes
既然这两个都是真的,为什么它不给儿子(哈里,查尔斯)一个是的?作为一个重要的注意事项,这确实使用不连续谓词警告进行编译:
compiling /Users/nicolejulian/Dropbox/AI/test.pl for byte code...
/Users/nicolejulian/Dropbox/AI/test.pl:4: warning: discontiguous predicate father/2 - clause ignored
/Users/nicolejulian/Dropbox/AI/test.pl:5: warning: discontiguous predicate father/2 - clause ignored
/Users/nicolejulian/Dropbox/AI/test.pl:6: warning: discontiguous predicate daughter/2 - clause ignored
/Users/nicolejulian/Dropbox/AI/test.pl:7: warning: discontiguous predicate son/2 - clause ignored
/Users/nicolejulian/Dropbox/AI/test.pl compiled, 8 lines read - 617 bytes written, 11 ms
(1 ms) yes
之前的一些实验让我觉得我基本上可以在警告和无限循环之间进行选择,所以我照样做了。(例如,将所有左侧标签分组将删除警告,但随后导致查询|?-father(elizabeth,george)。
崩溃)
无论如何,如果我不能只是“欺骗”和添加son(harry,charles)
作为事实,我对Prolog的执行步骤有什么不理解的呢 您显示的警告中的关键短语是被忽略的子句。所以你的父子逻辑,过去的一切都被忽略了。尝试使它们相邻:
father(charles, harry).
father(X, Y) :- son(Y, X).
father(X, Y) :- daughter(Y, X).
daughter(elizabeth, george).
daughter(X, Y) :- \+son(X, Y), father(Y, X).
son(william, charles).
son(X, Y) :- \+daughter(X, Y), father(Y, X).
然后,您将得到true作为您的查询的答案
但是如果在true
之后键入a
(询问所有解决方案),则逻辑中还有一个问题。它不是优雅地结束,而是进入循环并溢出堆栈。这是由于父亲、儿子和女儿之间的循环逻辑。所以你可能想仔细考虑这一部分
为了绕过循环逻辑,考虑下面给出的例子。本案例使用了person
(给出姓名、性别和每一个父项,然后使用谓词建立这些关系和其他关系,通过基于事实而不是无限循环回到其他谓词来避免循环。可能还有其他类似的方法,但这是一个例子。我觉得这是一个带有tabling的Prolog(如YAP Prolog、Bprolog等)可以处理这样的相互递归规则,但我自己从来没有尝试过。什么叫“忽略?”其他使用父亲后面列出的事实的查询(charles,harry)
看起来确实有效,所以它毕竟理解了一些东西…?@nicole第2行和第6行都是女儿/2
的子句。警告告诉您它忽略了第6行的子句,因为它不在第2行的子句旁边。(反之亦然)。所以它忽略了其中一行,而只使用了另一行。@nicole你也可以告诉SWI不要把这当作指令的问题。:-不连续的女儿/2
将指示它期望女儿/2
的子句出现在中间。@mbrach不,实际上我同意你在answ结束时说的话呃,一个更好的方法(至少在“正常”Prolog的限制范围内)是重新构造代码,这样就不会出现循环递归。根据我的经验,添加剪切通常会使问题变得更糟。:)如果可以使用once/1
,语义会更清晰,我更喜欢它。顺便说一句,很有趣的是,列表示例就是这个问题。
father(charles, harry).
father(X, Y) :- son(Y, X).
father(X, Y) :- daughter(Y, X).
daughter(elizabeth, george).
daughter(X, Y) :- \+son(X, Y), father(Y, X).
son(william, charles).
son(X, Y) :- \+daughter(X, Y), father(Y, X).