Prolog Nim Game - 超出本地堆栈错误

时间:2011-02-11 00:43:31

标签: prolog logic-programming

我最近一直在做一些Prolog。我读过Prolog的艺术书。他们在那里有一个Nim游戏实现。所以我把它重写为SWI-Prolog,除了本地堆栈错误之外,一切似乎都很好。 经过调试后,我发现它似乎在程序的这一部分永远循环:

nim_sum([N|Ns],Bs,Sum):-
      binary(N,Ds), nim_add(Ds,Bs,Bs1), nim_sum(Ns,Bs1,Sum).
nim_sum([],Sum,Sum).

nim_add(Bs,[],Bs).
nim_add([],Bs,Bs).
nim_add([B|Bs],[C|Cs],[D|Ds]):-
    D is (B+C) mod 2, nim_add(Bs,Cs,Ds).

有人遇到过这种问题吗?对于某些替代实施的任何建议?

1 个答案:

答案 0 :(得分:2)

为避免“堆栈外”问题,通常需要以“最后调用优化”或“尾递归”形式编写递归谓词。

这里似乎应该颠倒 nim_sum / 3 的两个子句(首先放置“fact”子句,这是终止条件)。然后,调用 nim_sum / 3 会在具有正文的子句中自行创建,而不会打开任何回溯点(假设二进制/ 2 nim_add / 3 是确定性的。)

尝试交换 nim_sum 的这两个子句,并告诉我们它是如何工作的。

已添加:在进一步思考 nim_add / 3 之后,我怀疑Prolog引擎可能无法检测到它是确定性的,即仅以单向成功。这是削减工作!运营商。最简单的解决方案是在 nim_sum / 3 调用自身的位置前面添加一个剪切,这样在递归调用时肯定没有打开回溯点。然而,这更像是Prolog的“精神”:

nim_sum([],Sum,Sum).  
nim_sum([N|Ns],Bs,Sum):-  
    binary(N,Ds),  
    nim_add(Ds,Bs,Bs1),  
    nim_sum(Ns,Bs1,Sum).  

nim_add(Bs,[],Bs) :- !.  
nim_add([],Bs,Bs) :- !.  
nim_add([B|Bs],[C|Cs],[D|Ds]):-  
    D is (B+C) mod 2,  
    nim_add(Bs,Cs,Ds).  

这又假设二进制/ 2 是确定性的,可能是将整数(非负?)转换为0和1的最低有效位列表。