我似乎无法理解prolog(gprolog)的一些行为。作为一些背景,旋转应该比较两个列表并查看它们是否已被移位(如下所示)。
?- rotate(1,[4,1,2,3],[1,2,3,4]).
应该返回true。但是,当提出上述问题时,prolog似乎并不尊重规则排序。
rotate(0,[],[],[]).
%base case
rotate(0,[],[H|T1],[H|T2]):- rotate(0,[],T1,T2).
%recurse over the remainder list (the first list from S to the end)
时,Prolog将忽略下面的谓词
rotate(S,[H|T1],[H|T2],L):-S=:=0,rotate(0,T1,T2,L).
%recurse over the elements from S to the end of list1
从另一个谓词(直接在下面)回溯。
rotate(S,[H|T1],L,T2):-S > 0,S1 is S - 1,rotate(S1,T1,L,[H|T2]).
%add elements 1 to S into the remainder list
rotate(S,L1,L2):-len(L1,Len),S1 is S mod Len,!,rotate(S1,L1,L2,[]).
%ensure the shift is not out of bounds, call rotate/4
%utility function because couldn't use length
len([],Ret,Ret).
len([_|T],Len,Ret):-Len1 is Len+1,len(T,Len1,Ret).
len(L,Len):-len(L,0,Len).
我通过跟踪它发现了这种行为,并且坦率地感到困惑的是为什么它不会回溯并命中下一个谓词,而是失败并返回false。
我也愿意采用更好的方法来实现这一目标,因为这是中期的实践。
答案 0 :(得分:0)
抱歉,我对你的主要问题没有答案。跟踪执行以确定回溯行为是一种“最后的机会”,在调试Prolog时,你最好相信引擎 - 也因为它发生调试器有时会出错:)
当您有一个谓词的N个替代词时,您可以在测试后立即为每个前N-1个子句放置剪切,然后您可以(最终)避免在最后一个中进行测试。
目的很明确:将执行提交到成功路径。相反,你做了相反的,把切割放在最后一个rotate / 4子句中,它没用。所以,这不应该是罪魁祸首,只是表示你尚未掌握Prolog编程模型的细微差别......
我还建议避免'早期优化'你的任务:当逻辑正确时,程序应该独立于S大于列表长度而工作。相反,也许您应该考虑如果否定 S作为参数给出会发生什么。
如果你'声明性'调试,你的谓词似乎不起作用:
?- rotate(2,[4,1,2,3],R).
R = [2, 3, 1, 4] ;
false
我会期待[2, 3, 4, 1]
,即这个更简单定义的结果
rotate(N, L, R) :- N > 0, N1 is N-1, rotate(L, T), rotate(N1, T, R).
rotate(0, L, L).
rotate([X|Xs],R) :- append([Xs,[X]],R).
rotate / 2使用方便的append / 2助手来“发送回”头部。我相信你可以用append / 3或你自己的定义替换它......