PySwip调用递归Prolog查询触发栈溢出PrologError问题求助
解决PySwip调用Prolog递归规则时的栈溢出问题
问题根源
你的Prolog递归规则存在无限递归隐患:
on(X, Z) :- on(X, Y), on(Y, Z).
SWI-Prolog交互模式下,查询on(a,c)时默认返回第一个匹配的事实后就停止,不会触发后续递归枚举;但PySwip的prolog.query()会尝试收集所有可能的解,递归规则会不断生成更深的链式查询(比如on(a,c)→on(a,Y),on(Y,c)→on(a,Y'),on(Y',Y),on(Y,c)...),最终导致栈溢出。
解决方案
方案1:拆分谓词(推荐,彻底避免无限递归)
将直接相邻关系和传递闭包关系拆分为两个独立谓词,递归仅基于直接关系展开:
% 定义直接相邻的on关系 direct_on(a, b). direct_on(b, c). % 定义传递闭包的on关系 on(X, Z) :- direct_on(X, Z). on(X, Z) :- direct_on(X, Y), on(Y, Z).
此时无论在SWI-Prolog还是PySwip中查询on(a,c),都会正确返回结果且不会触发无限递归。
方案2:给原递归规则添加终止约束
如果不想拆分谓词,可以在递归规则中添加约束,避免循环链生成:
on(a, b). on(b, c). on(X, Z) :- on(X, Y), on(Y, Z), X \= Z, Y \= Z.
该约束确保递归过程中不会出现循环,但这种方式不如拆分谓词直观,且可能遗漏部分合法解。
验证修正后的Python代码
使用方案1的Prolog代码,Python脚本运行结果如下:
from pyswip import Prolog prolog = Prolog() prolog.consult("test.pl") print(list(prolog.query("on(a,c)"))) # 输出: [{}, ...](返回所有匹配的有效解)
临时调整栈大小(仅治标)
如果因特殊需求必须保留原递归规则,可以临时增大Prolog的栈限制:
from pyswip import Prolog prolog = Prolog() prolog.query("set_prolog_stack(local, limit(2000000))") # 调整本地栈内存上限 prolog.consult("test.pl") print(list(prolog.query("on(a,c)")))
但这只是临时缓解手段,无法从根本上解决无限递归问题。
内容的提问来源于stack exchange,提问作者MTD
相关产品推荐
相关产品推荐

