Prolog重新发起呼叫,并没有明显的原因失败
我对Prolog相当陌生。无论如何,我试图编写一套递归规则,返回给定字符代码列表中每个单词的平均字符数。我的代码如下。Prolog重新发起呼叫,并没有明显的原因失败
medellangd(Text,AvgLen) :-
medellangd(Text,T,1,0,0),
AvgLen = T.
medellangd([],AvgLen,Space,Words,Chars) :-
T is (Chars/Words),
AvgLen = T.
medellangd([A|B],AvgLen,Space,Words,Chars) :-
succ(Chars,C),
updatewords(A,Space,Words,W),
updatespace(A,S),
medellangd(B,T,S,W,C),
AvgLen = T.
updatewords(A,1,Words,W) :-
member(A, [65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122])
-> succ(Words,S),
W = S
; W = Words.
updatewords(A,0,Words,W) :-
W = Words.
updatespace(A,S) :-
member(A,[65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122])
-> S = 0
; S = 1.
,其原因我也说不上来,虽然AvgLen得到正确的值,序言当我打电话medellangd([68,69],AvgLen)返回false。当我跟踪这个调用时,尽管每次调用最初在AvgLen获取其值之前退出,但如果在AvgLen值赋值之后输入分号,并且失败,则Prolog决定重做“(9)更新字(68,1,0,_G2574)” 。为什么会发生?
你的谓词工作正常,为了找到一个解决方案prolog尝试一切可能的方式,所以在给出答案AvgLen = 2之后,我们可以找到更多可行的解决方案。当Prolog试图找到一个解决方案时,它会建立一个证明树,在那里它保存所有可能的方法来证明目标,并逐一尝试它们,直到找到所有正确的答案,并且没有其他方法来证明目标已经离开。这是调用重做的原因,尝试更多可能的解决方案。如果你想谓词变成了确定性 您可以添加切(!):
medellangd(Text,AvgLen) :-
medellangd(Text,T,1,0,0),
AvgLen = T,!.
,当发现第一个正确的答案,不会再进一步搜索这些将停止。
一个简单的例子来了解如何工作序言是:如果你查询simple_example(L)
simple_example([]).
simple_example([_]).
以上谓词成功。其中L是空的或它有一个元素。 现在,如果您尝试查询simple_example([])。或simple_example([1])。在跟踪你会看到:
[trace] ?- simple_example([1]).
Call: (7) simple_example([1]) ? creep
Exit: (7) simple_example([1]) ? creep
true.
在另一方面,如果你写的同一个例子是不同的:
simple_example2(L):- L=[].
simple_example2(L):- L=[_].
谓词simple_example2显然是相当于simple_example但是如果你查询simple_example2([])。在跟踪你会看到,因为我们有[]在simple_example2同时匹配l在会尝试这两种,当然只有第一个将是正确的:
[trace] ?- simple_example2([1]).
Call: (7) simple_example2([1]) ? Unknown option (h for help)
Call: (7) simple_example2([1]) ? Unknown option (h for help)
Call: (7) simple_example2([1]) ? Unknown option (h for help)
Call: (7) simple_example2([1]) ? creep
Call: (8) [1]=[] ? creep
Fail: (8) [1]=[] ? creep
Redo: (7) simple_example2([1]) ? creep
Call: (8) [1]=[_G3328] ? creep
Exit: (8) [1]=[1] ? creep
Exit: (7) simple_example2([1]) ? creep
true.
是否有可能在算法上确保在证明树中只有一个Prolog路径? –
不,它不需要算法,但prolog如何理解是否有更多的解决方案。这是prolog搜索的主要特征,我将更新答案以解释prolog如何以一个非常简单的例子作出选择,但是在更复杂的程序中,确保prolog没有其他选项是没有意义的。 Againg如果你只想要一个解决方案,你可以使用剪切。 – coder
你有什么想法在我的情况下会导致失败吗? –
我几乎可以肯定,你的'updatewords/4'就是选择点来自于。顺便说一下,我不明白你为什么要在谓词定义的末尾做所有这些显式的统一...你有没有理由? – 2016-09-17 20:47:10