我正在Prolog中使用术语和签名(一阶谓词逻辑(。
我的签名是(∅, Z, {add(2), sub(2), mult(2)})
。所以没有变量,常数是整数,函数是";加上"sub";以及";mult";。
目标是编写谓词";calc/2";,它取一个项(给定上面的签名(,并根据整数的加法、减法和乘法的通常定义进行计算。示例:
?- calc( add(sub(8,2), mult(4,-3)), N).
N = -6
(由于((8−2(+(4*−3((=−6(
这个问题类似于这个问题,但有一个很大的区别是我需要避免使用=。。运算符来查找函数的名称。相反,我想利用Prolog在规则的参数上使用模式匹配的事实,这是我完全坚持的;加上"sub";,以及";mult";不应该是谓词。
我的第一个解决方案使用=。。操作员是(在上面链接的线程的答案的帮助下(:
op(+, add).
op(-, sub).
op(*, mult).
calc(Term, N) :-
calc2(Term, Expr),
N is Expr.
calc2(N,N) :- integer(N).
calc2(Term, Expr) :-
Term =.. [Op_str, Comp1, Comp2],
op(Op, Op_str),
calc2(Comp1, Expr1),
calc2(Comp2, Expr2),
Expr =.. [Op, Expr1, Expr2].
但由于这不是我正在寻找的解决方案,它对我的问题没有太大帮助。
我可以很容易地执行单个计算(如calc(add(1,2), N)
(,但我很难处理比这更复杂的事情。
要使用模式匹配并避免univ运算符=。。,你可以这样重写calc2/2:
calc2(add(Op1, Op2), Expr1 + Expr2) :-
calc2(Op1, Expr1),
calc2(Op2, Expr2).
calc2(sub(Op1, Op2), Expr1 - Expr2) :-
calc2(Op1, Expr1),
calc2(Op2, Expr2).
calc2(mult(Op1, Op2), Expr1 * Expr2) :-
calc2(Op1, Expr1),
calc2(Op2, Expr2).
这使得代码更加直观,其中可以通过单独的子句处理额外的情况(例如电源(。此外,现代编译器可以优化生成的代码。