如何在Prolog中传递谓词作为另一个谓词的参数?

时间:2014-10-19 17:54:20

标签: parameters prolog expression predicate

我有这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))

3 个答案:

答案 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