简体   繁体   English

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

[英]Prolog Nim Game - Out of local stack error

I've been doing some Prolog lately. 我最近一直在做一些Prolog。 And I've read The Art Of Prolog book. 我读过Prolog的艺术书。 They have a Nim game implementation there. 他们在那里有一个Nim游戏实现。 So I've rewritten it to SWI-Prolog and everything seems fine except this Out of local stack error. 因此,我已将其重写为SWI-Prolog,除了出现Out of local stack错误外,其他一切似乎都不错。 After debugging I've found out that it seems to loop forever in this part of the program: 调试之后,我发现它似乎在程序的这一部分永远循环:

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).

Did anybody run into this kind of problem? 有没有人遇到过这种问题? Any suggestions for some alternative implementation? 对于某些替代实施的任何建议?

To avoid "out of stack" problems it is often necessary to write the recursive predicates in a "last call optimization" or "tail recursive" form. 为了避免“栈外”问题,通常有必要以“最后调用优化”或“尾递归”形式编写递归谓词。

Here it seems the two clauses for nim_sum/3 should be reversed (putting the "fact" clause first, which is the termination condition). 在这里,似乎应该反转nim_sum / 3的两个子句(首先输入“ fact”子句,这是终止条件)。 Then the call nim_sum/3 makes to itself in the clause that has a body will be made without any backtrack points open (assuming binary/2 and nim_add/3 are deterministic). 然后调用nim_sum / 3使自己在具有正文的子句中没有任何回溯点打开(假设二进制/ 2nim_add / 3是确定性的)。

Try swapping those two clauses for nim_sum and let us know how it works. 尝试将这两个子句交换为nim_sum,并告诉我们它是如何工作的。

Added: After thinking further about nim_add/3 , I'm suspecting that the Prolog engine will probably not detect that it is deterministic, ie succeeds in only one way. 补充:在进一步思考nim_add / 3之后 ,我怀疑Prolog引擎可能无法检测到它是确定性的,即仅以一种方式成功。 This is a job for the cut ! 这是削减工作! operator. 运营商。 The simplest solution is to add one cut right in front of where nim_sum/3 calls itself, so that there are definitely no backtrack points open at the time the recursive call is made. 最简单的解决方案是在nim_sum / 3调用自身的位置前面添加一个剪切,这样在递归调用时肯定没有打开回溯点。 However this is more "in the spirit" of Prolog: 但是,这更符合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).  

Again this assumes binary/2 is deterministic, presumably converting an integer (nonnegative?) into a list of 0's and 1's, least significant bits first. 同样,这假设二进制/ 2是确定性的,可能是将整数(非负?)转换为0和1的列表,首先是最低有效位。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM