Prolog 序言加法练习

Prolog 序言加法练习,prolog,successor-arithmetics,Prolog,Successor Arithmetics,我用这个非常简单的代码来表示数字。问题是当我使用add2函数时 示例:add2(s(0)+s(s(0)),s(s(0)),Z)。正确返回s(s(s(s(0))))。但是add2(0,s(0)+s(s(0)),Z)。始终返回s(0)+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)) :- ad

我用这个非常简单的代码来表示数字。问题是当我使用add2函数时

示例:
add2(s(0)+s(s(0)),s(s(0)),Z)。
正确返回
s(s(s(s(0))))
。但是
add2(0,s(0)+s(s(0)),Z)。
始终
返回s(0)+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).

在Prolog函数中,中缀
+
等符号不计算。似乎您正在尝试评估所有出现的
+
。但是,其中一些仍然没有进行评估,如果您尝试像
add2/3
中那样临时执行此操作,这可能会非常棘手。考虑
add2(0+0+0,0,R)
这与您的定义不符

您所称的
numeric/1
最好称为
expression/1

考虑定义一个辅助谓词
eval/2
,将表达式简化为s(X)-数。
然而,请注意,对于像
add2(0,0,0+0)
这样的目标,即使这样的定义也会失败。这是一个固有的问题,只能使用约束或类似的技术来解决…

这是因为第一个
add2
子句和第一个
add
子句的组合。您的
add2(0,……)
将触发
add(0,…)
,它始终统一第二个和第三个参数。

当您调用
add2(0,s(0)+s(s(0)),Z)
时,它将与
add2/3
的第一个子句统一,因为第一个子句的头部只有三个变量,因此,它可以与
add2/3
的任何调用相统一。在您的示例中,这反过来会导致调用
add/3
的第一个子句,因此Z将绑定到
s(0)+s(0))

代码的问题在于,
add2/3
中更具体的条款放在一般条款之后。因此,要使代码正常工作,请将
add2/3
的第一个子句放在最后,并将剪切添加到其他两个子句中,例如

add2(X+Y,Z,R) :- !,add(X,Y,A),add2(A,Z,R).

因为当该子句的头与查询匹配时,您可以确定您执行的是正确的子句,并且回溯不会有问题。

好吧,这是一个简单的家庭作业练习,所以我想要求输入正确插入括号(如果是单词…)是可以的。但是:如果您确实担心像
add2(0+0+0,0,R)
这样的情况,那么请替换
add2/3
的两个子句中的
add/3
调用,它们处理带有
add2/3
调用的+运算符,例如
add2(X+Y,Z,R):-!,Add2(x,y,a),Add2(a,z,r).< /代码>。考虑添加<代码> Mul2/3 或函子<代码>(*)/ 2 < /代码>,看看为什么一个单独的定义是有意义的-也作为家庭作业。当然,但这可能很快超出了他目前的作业范围。此外,它还转移了一个更基本的问题,即在他的代码中,
add2/3
的泛型子句被置于特定子句之前。如果一个人在Prolog的基础知识上苦苦挣扎,而不是期望他不仅解决加法问题,还要编写一个通用表达式解析器/求值器,这是一项雄心勃勃的任务。