SWI-Prolog填字游戏求解代码递归谓词调用失败问题咨询
填字游戏SWI-Prolog递归调用失败排查方案
1. 优先排查低级错误
以下错误是直接导致谓词返回false的核心原因:
- 拼写错误:第三个
do_something_else子句的递归调用写错为do_something_elese,多了一个字母e,Prolog无法匹配到对应谓词直接返回失败。 - 谓词名错误:
do_something子句的递归调用写为X,明显是笔误,应该是do_something,没有对应定义的谓词必然调用失败。
2. 修复参数传递错误
你代码中所有子句已经在头部绑定了crss结构体的参数,但后续调用其他谓词时又重新用匿名变量_占位crss的其他字段,会导致已经绑定的结构体参数(比如填字游戏尺寸、题目列表)丢失,space_length等辅助谓词无法拿到正确参数返回预期值。
修复方式是直接传递整个crss结构体变量,不需要重复解构:
% 错误写法,匿名变量会丢失结构体前三个参数 do_something_else(crss(_, _, PL, [H | T]), Q, [CL | L]) :-space_length(crss(_, _, PL, _), Q, Len),... % 正确写法,头部直接给结构体命名,后续直接传递 do_something_else(Crss, Q, [CL | L]) :- Crss = crss(_, _, PL, [H | T]), space_length(Crss, Q, Len), ... do_something_else(Crss, Q, L).
3. 校验截断符逻辑
do_something_else第一个非终止子句加了截断符!,会阻止后续回溯匹配。如果你需要返回多组候选答案可以删除这个截断符,如果只需要第一组符合条件的结果可以保留。
修复后参考代码
% 修复拼写、参数传递问题的do_something_else do_something_else(_, _, [], []). do_something_else(Crss, Q, [H | T], [CL | L]) :- space_length(Crss, Q, Len), atom_chars(H, CL), length(CL, Ln), Ln == Len, !, do_something_else(Crss, Q, T, L). do_something_else(Crss, Q, [H | T], L) :- space_length(Crss, Q, Len), atom_chars(H, CL), length(CL, Ln), Ln =\= Len, do_something_else(Crss, Q, T, L). % 修复递归谓词名、参数传递问题的do_something do_something(_, [], []). do_something(Crss, [H | T], [(H, L) | List]) :- Crss = crss(_, _, _, V), do_something_else(Crss, H, V, L), do_something(Crss, T, List). % 修复参数传递问题的pos_sol pos_sol(Crss, []) :- Crss = crss(_, _, _, []). pos_sol(Crss, List) :- questions(Crss, LI), questions_text(LI, LIT), do_something(Crss, LIT, List).
通用调试手段
如果修复后仍然存在问题,可以用SWI-Prolog自带的跟踪工具定位:
- 输入
trace.开启调用跟踪 - 执行你的目标调用
pos_sol(你的crss结构体变量, Result). - 逐行查看谓词匹配和参数绑定情况,找到返回false的节点即可定位具体问题。
内容的提问来源于stack exchange,提问作者theo1002
相关产品推荐
相关产品推荐

