Prolog 重做一个调用并无缘无故地失败
Prolog redoes a call and fails for no apparent reason
我对 Prolog 还很陌生。无论如何,我正在尝试编写一组递归规则,即 return 给定字符代码列表中每个单词的平均字符数。我的代码如下。
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) 时 Prolog returns 为假。当我跟踪这个调用时,尽管每个调用最初都是在 AvgLen 获取其值之前退出的,但如果我在 AvgLen 值赋值后输入分号,Prolog 决定重做“(9) updatewords(68, 1, 0, _G2574)”,但失败了.为什么会这样?
你的谓词工作正常,为了找到一个解决方案序言尝试了所有可能的方法,所以在给出答案 AvgLen=2 之后它会搜索更多可能的解决方案。当 Prolog 试图找到一个解决方案时,它会构建一个证明树,其中保留所有可能的方法来证明目标并逐一尝试它们,直到找到所有正确的答案并且没有其他方法可以证明目标已经存在。这就是调用重做以尝试更多可能解决方案的原因。如果您希望谓词是确定性的
您可以在以下位置添加剪切 (!):
medellangd(Text,AvgLen) :-
medellangd(Text,T,1,0,0),
AvgLen = T,!.
当找到第一个正确答案时,这些将停止并且不会进一步搜索。
一个简单的例子来理解序言的工作原理是:
simple_example([]).
simple_example([_]).
如果查询simple_example(L),则上述谓词成功。其中 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([])。在 trace 中你会看到,因为我们有 [] 匹配 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 还很陌生。无论如何,我正在尝试编写一组递归规则,即 return 给定字符代码列表中每个单词的平均字符数。我的代码如下。
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) 时 Prolog returns 为假。当我跟踪这个调用时,尽管每个调用最初都是在 AvgLen 获取其值之前退出的,但如果我在 AvgLen 值赋值后输入分号,Prolog 决定重做“(9) updatewords(68, 1, 0, _G2574)”,但失败了.为什么会这样?
你的谓词工作正常,为了找到一个解决方案序言尝试了所有可能的方法,所以在给出答案 AvgLen=2 之后它会搜索更多可能的解决方案。当 Prolog 试图找到一个解决方案时,它会构建一个证明树,其中保留所有可能的方法来证明目标并逐一尝试它们,直到找到所有正确的答案并且没有其他方法可以证明目标已经存在。这就是调用重做以尝试更多可能解决方案的原因。如果您希望谓词是确定性的 您可以在以下位置添加剪切 (!):
medellangd(Text,AvgLen) :-
medellangd(Text,T,1,0,0),
AvgLen = T,!.
当找到第一个正确答案时,这些将停止并且不会进一步搜索。
一个简单的例子来理解序言的工作原理是:
simple_example([]).
simple_example([_]).
如果查询simple_example(L),则上述谓词成功。其中 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([])。在 trace 中你会看到,因为我们有 [] 匹配 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.