GNU Prolog中member谓词实现疑问:与《Prolog编程艺术》的差异
Prolog代码运行疑问与差异解析
问题背景
我用《Prolog编程艺术》里的代码在GNU Prolog中运行时遇到问题,原代码及运行警告如下:
mem(X,[X|Xs]). % user:2: warning: singleton variables [Xs] for mem/2 mem(X,[Y|Ys]) :- mem(X,Ys). % user:3: warning: singleton variables [Y] for mem/2
测试查询时出现错误:
| ?- mem(g, [a, g, e]). uncaught exception: error(existence_error(procedure,mem/2),top_level/0)
我理解单例变量是仅使用一次的变量,于是修改代码解决了警告:
mem(X, [X|_]). mem(X, [_|Ys]) :- mem(X, Ys).
修改后查询结果:
| ?- mem(b, [a, b, c]). true | ?- mem(d, [a, b, c]). no
疑问
- 为什么第二个查询返回
no而非false? - 为何GNU Prolog与《Prolog编程艺术》中的示例存在差异?是Prolog标准变化导致的吗?
解答
1. 关于返回no而非false的原因
这就是不同Prolog实现的输出习惯差异,意思完全相同:都表示当前查询找不到符合条件的解。
- GNU Prolog、部分SWI-Prolog交互模式里,查询失败就输出
no; - 有些Prolog环境会输出
false,只是控制台显示的字符串不同,逻辑上没有任何区别。
2. GNU Prolog与书中示例的差异原因
(1)单例变量警告
书中代码出现警告,是因为当年的Prolog实现对单例变量的检查没那么严,而现代GNU Prolog默认开启了严格检测——它会提醒你代码里存在只用过一次的变量,这类变量要么是笔误,要么可以用匿名变量_代替(就像你修改后的代码那样)。这不是Prolog标准变了,只是不同实现的默认配置不一样。
(2)existence_error(procedure,mem/2)错误
这个错误说明GNU Prolog没找到mem/2这个谓词,大概率是你输入原代码时没正确加载(比如输入到一半中断、没把两行代码都提交给解释器),和代码逻辑本身无关。你修改后的代码能正常运行,也能证明这一点。
(3)代码写法差异
书中用Xs、Y作为单例变量,现代Prolog推荐用_,这是代码风格的优化,不是语法标准的变化——早年Prolog允许单例变量存在,只是现代实现会通过警告帮开发者避免潜在错误。
内容的提问来源于stack exchange,提问作者notaorb
相关产品推荐
相关产品推荐

