Prolog 加法练习
我有这个非常简单的代码作为数字的表示。问题是当我使用 add2 函数时。
示例:add2(s(0)+s(s(0)), s(s(0)), Z)。
返回 s(s(s(s(s(0) )))))
正确。但是,add2(0, s(0)+s(s(0)), Z).
始终返回 s(0)+s(s(0))
。谁能明白为什么会发生这种情况?
numeral(0).
numeral(s(X)) :- numeral(X).
numeral(X+Y) :- numeral(X), numeral(Y).
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
%% exercise 1
add2(X,Y,R) :- add(X,Y,R).
add2(X+Y,Z,R) :- add(X,Y,A),add2(A,Z,R).
add2(X,Y+Z,R) :- add(Y,Z,A),add2(X,A,R).
I have this very simple code as a representation of numerals. The problem is when I use the add2 function.
Example: add2(s(0)+s(s(0)), s(s(0)), Z).
returns s(s(s(s(s(0)))))
correctly. However add2(0, s(0)+s(s(0)), Z).
always returns s(0)+s(s(0))
. Can anyone see why this is happening?
numeral(0).
numeral(s(X)) :- numeral(X).
numeral(X+Y) :- numeral(X), numeral(Y).
add(0,X,X).
add(s(X),Y,s(Z)) :- add(X,Y,Z).
%% exercise 1
add2(X,Y,R) :- add(X,Y,R).
add2(X+Y,Z,R) :- add(X,Y,A),add2(A,Z,R).
add2(X,Y+Z,R) :- add(Y,Z,A),add2(X,A,R).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
发生这种情况是因为第一个
add2
子句和第一个add
子句的组合。您的add2(0, ..., ...)
将触发add(0, ..., ...)
,它始终统一第二个和第三个参数。It's happening because of the combination of the first
add2
clause and the firstadd
clause. Youradd2(0, ..., ...)
will triggeradd(0, ..., ...)
which always unifies the second and third argument.在 Prolog 中,中缀
+
之类的函数符号不会被求值。您似乎正在尝试评估所有出现的+
。然而,其中一些仍然没有被评估,如果您尝试像add2/3
中那样临时执行此操作,这可能会非常棘手。考虑add2(0+0+0,0,R)
因您的定义而失败。您所说的
numeral/1
可能更好地称为expression/1
。考虑定义一个辅助谓词
eval/2
将表达式简化为 s(X) 数字。但请注意,对于像
add2(0,0,0+0)
这样的目标,即使这样的定义仍然会失败。这是一个固有的问题,只能使用约束或类似的技术来解决......In Prolog function symbols like the infix
+
are not evaluated. It seems you are trying to evaluate all occurrences of+
. However, some of them are still not evaluated and this can be quite tricky if you try to do this ad hoc as inadd2/3
. Consideradd2(0+0+0,0,R)
which fails with your definition.What you call
numeral/1
might better be calledexpression/1
.Consider to define an auxiliary predicate
eval/2
to simplify expressions to s(X)-numbers.Note however, that even such a definition will still fail for goals like
add2(0,0,0+0)
. This is an inherent problem which can only be solved using constraints or similar techniques...当调用
add2(0, s(0)+s(s(0)), Z)
时,会与add2/3
的第一个子句统一,由于第一个子句的头部只有三个变量,因此它可以与任何add2/3
调用统一。这反过来将在您的示例中导致调用add/3
的第一个子句,因此 Z 将绑定到s(0)+s(s(0))
。您的代码的问题在于,
add2/3
的更具体子句放置在通用子句之后。因此,为了使您的代码正常工作,请将add2/3
的第一个子句放在最后,并对其他两个子句添加剪切,例如,因为当该子句的头部与查询匹配时,您确定你正在执行正确的子句,并且你不会在回溯时遇到麻烦。
When you call
add2(0, s(0)+s(s(0)), Z)
, it will be unified with the first clause ofadd2/3
, since this first clause only has three variables in the head, so it can be unified with any call ofadd2/3
. This in turn will in your example lead to calling the first clause ofadd/3
, so Z will be bound tos(0)+s(s(0))
.The problem with your code is that the more specific clauses of
add2/3
are placed after the general clause. So to make your code work, place the first clause ofadd2/3
last, and add cuts to the other two, e.g.since when the head of that clause has matched the query, you're sure that you're executing the right clause and you won't have trouble on backtracking.