Prolog实现骑士与无赖谜题时card/2未知过程错误求解
骑士与无赖谜题Prolog实现问题排查
第一个实现(调用card/2报错)的问题
你遇到的Unknown procedure card/2报错根因如下:
- 你定义的
false()谓词仅覆盖了相等判断、合取、析取三类结构的否定逻辑,没有适配card/2结构的处理规则 - 当自定义
says算子处理B的陈述时,如果B是无赖,会调用false(card([1], [...])),系统找不到card/2的实现也找不到对应的false处理分支,直接抛出未定义过程错误 - 你原先
question3谓词里用的card/2是sat/1约束库的专用算子,仅能在sat()括号内部使用,无法在自定义的命题逻辑中直接调用
第二个实现(统计骑士数量结果错误)的问题
结果不正确的根因是普通Prolog求值是即时执行的,不支持约束延迟求解:
- 你调用
counte(knight,[A,B,C],Knights)时,A、B、C三个变量还没有绑定为knight或knave,普通的合一判断E = H和算术运算is无法处理未绑定的变量,统计出来的Knights值是错误的不确定值 - 后续的
#=约束虽然是CLP(FD)的约束算子,但输入的Knights已经是错误值,自然无法得到正确结果
修复方案
方案1:修改B的陈述适配现有逻辑
最简单的修复是把「恰好有一个骑士」的陈述转成你false()谓词已经支持的合取+析取形式,不需要引入额外算子:
:- op(900,xfy,says). knight says S :- S. knave says S :- false(S). false(A = B) :- dif(A,B). false( (A ; B) ) :- false(A), false(B). false( (A , B) ) :- false(A); false(B). question3_again(A,B,C) :- % A的陈述不变 A says ( A = knave, B = knave, C = knave ), % 把B的陈述转成枚举形式 B says ( (A = knight, B = knave, C = knave); (A = knave, B = knight, C = knave); (A = knave, B = knave, C = knight) ), % 补充取值范围限制,过滤无效解 member(A, [knight, knave]), member(B, [knight, knave]), member(C, [knight, knave]).
运行后可得到正确结果:A = knave, B = knight, C = knave。
方案2:改用CLP(FD)约束实现计数
如果要保留计数逻辑,需要用CLP(FD)的约束算子替代普通的统计函数,支持延迟求值:
:- use_module(library(clpfd)). :- op(900,xfy,says). knight says S :- S. knave says S :- false(S). false(A = B) :- dif(A,B). false( (A ; B) ) :- false(A), false(B). false( (A , B) ) :- false(A); false(B). false(A #= B) :- A #\= B. question3_again(A,B,C) :- % 把骑士/无赖映射为1/0,用CLP(FD)约束求和 AVal #<==> A #= knight, BVal #<==> B #= knight, CVal #<==> C #= knight, Knights #= AVal + BVal + CVal, % 原有陈述逻辑不变 A says ( Knights #= 0 ), B says ( Knights #= 1 ), % 补充取值范围限制 member(A, [knight, knave]), member(B, [knight, knave]), member(C, [knight, knave]).
内容的提问来源于stack exchange,提问作者Luiz
相关产品推荐
相关产品推荐

