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)” 。为什么会发生?

+0

我几乎可以肯定,你的'updatewords/4'就是选择点来自于。顺便说一下,我不明白你为什么要在谓词定义的末尾做所有这些显式的统一...你有没有理由? – 2016-09-17 20:47:10

你的谓词工作正常,为了找到一个解决方案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. 
+0

是否有可能在算法上确保在证明树中只有一个Prolog路径? –

+0

不,它不需要算法,但prolog如何理解是否有更多的解决方案。这是prolog搜索的主要特征,我将更新答案以解释prolog如何以一个非常简单的例子作出选择,但是在更复杂的程序中,确保prolog没有其他选项是没有意义的。 Againg如果你只想要一个解决方案,你可以使用剪切。 – coder

+0

你有什么想法在我的情况下会导致失败吗? –