我有这3个谓词:
times(X, Y):-
Result is X * Y.
minus(X, Y):-
Result is X - Y.
plus(X, Y):-
Result is X + Y.
我希望在times(2,2)
中传递plus(X, Y)
,例如plus(times(2,2), minus(X, Y))
。
答案 0 :(得分:4)
首先,您需要了解Prolog谓词实际描述的内容:它们不是函数,而是值之间的关系。因此,如果您想要添加谓词,则需要使用三个参数作为谓词:plus(A, B, Sum)
。因此,在Prolog中,结果不像许多其他语言那样免费出现。
而不是
plus(X, Y):-
Result is X + Y.
你需要写
plus(X, Y, Result) :-
Result is X + Y.
接下来要做的是进一步传递中间值。在支持函数的语言中,这是一项非常简单的任务。但在Prolog中,函数符号未被解释。因此,无论是对关系中的所有内容进行编码,还是以其他方式实现自己的(is)/2
版本。
对于初学者来说,宁愿坚持第一个选择。因此,而不是
..., plus(times(2,2), minus(X, Y)) ...
现在写
..., times(2, 2, R), plus(R, minus(X, Y), S), ...
S
是最终结果。
观察如果直接在关系中编码表达式,则必须引入上面的R
等中间变量。
很明显,(直接)关系符号对于像这样的目的来说不那么优雅。对于非常精确的区域,Prolog也提供表达式,特别是(is)/2
,然后是library(clpfd)
的更一般的设置。
但是,作为一个初学者,首先要习惯于关系符号是个好主意。首先研究successor arithmetics可能是一个更好的主意。在使用library(clpfd)
之前和使用(is)/2
之前。
答案 1 :(得分:4)
您的问题标题与问题文本之间的关系对我来说并不清楚,我认为@false可能是正确的,因为这里对Prolog存在更为根本的误解。我不知道这是否真的满足了你的需要,但这里的另一种选择就是编写你自己的评估者。
eval(times(X,Y), Result) :-
eval(X, XResult),
eval(Y, YResult),
Result is XResult * YResult.
eval(minus(X,Y), Result) :-
eval(X, XResult),
eval(Y, YResult),
Result is XResult - YResult.
eval(plus(X,Y), Result) :-
eval(X, XResult),
eval(Y, YResult),
Result is XResult + YResult.
需要对每个规则的主体内的eval/2
进行递归调用来处理plus(times(2,2), minus(X, Y))
等案例。然后你需要一个数字规则:
eval(Num, Num) :- number(Num).
这适用于以下情况:
?- eval(plus(times(2,2), minus(7,1)), Result).
Result = 10.
对于这样的案件,你没有任何好处:
?- eval(plus(times(2,2), minus(X,Y)), Result).
ERROR: Out of local stack
当然,如果我们在到达之前为X和Y建立了绑定,它会起作用,但是如果你想让它为X和Y生成可能的解决方案你运气不好,那么你需要使用clpfd
。如果你追踪到这个奇怪错误的原因是因为number(X)
当X
未绑定时为false,所以它实际上生成了涉及时间,减号和加号结构并尝试它们的新子句,不是你想要的评估者。
修改:实施printterm/1.
eval/2
谓词向您展示如何执行递归树遍历。制作漂亮的打印机的原理是一样的。我很懒,所以我只会草绘它,你必须自己填写细节。
printterm(T) :- format_term(T, Formatted), write(Formatted), nl.
format_term(plus(X,Y), Formatted) :-
format_term(X, XFormatted),
format_term(Y, YFormatted),
format(atom(Formatted), '(~a + ~a)', [XFormatted, YFormatted]).
% other format_term clauses here for other arithmetic expressions
format_term(X, X) :- number(X).
希望这有帮助!
答案 2 :(得分:2)
Daniel解决方案的替代方案是将plus(times(2,2), minus(5,3))
等术语视为支持一组操作的表达式对象,例如&# 34;评价"或"区分"。这允许您编写目标,例如:
| ?- plus(times(2,2), minus(5,3))::evaluate(Result).
Result = 6
yes
优点是适用于特定表达式的所有操作的规则,例如, times/2
整齐地封装在相应的对象中。即它们不是通过操作聚类谓词,而是通过(基本)表达式聚类。沿着这些行的一个例子,但在导出和简化表达式的上下文中可以找到here。