Prolog - 替代和评估

时间:2017-09-22 13:52:57

标签: prolog

好的编程人员。

与命令式编程相比,逻辑编程总是令人着迷。 由于追求未知的逻辑编程,遇到算术表达式时会遇到一些问题。

这是我到目前为止所做的代码。

hy

以添加操作为例:

number_atom(N) :-
(number(N) -> functor(N, _, _); functor(N, _, _), atom(N)).
arithmeticAdd_expression(V,V,Val,Val).
arithmeticAdd_expression(N, _Var, _Val, N) :-
   number_atom(N).

arithmeticAdd_expression(X+Y, Var, Val, R) :-
   arithmeticAdd_expression(X, Var, Val, RX),
   arithmeticAdd_expression(Y, Var, Val, RY),
   (number(RX), number(RY) -> R is RX + RY; R = RX + RY).

我想要达到的目标是       如果表达式中的原子只能被给定的变量和值替换,那么结果就是数字,就像上面显示的例子一样(结果= 11)。否则,结果只是表达式本身。我的代码问题出在那里,我可以搞清楚。所以,请有人可以帮助我吗?谢谢。

1 个答案:

答案 0 :(得分:3)

逻辑编程相对于函数式编程的一个重要吸引力在于,您通常可以在多个方向中使用相同的代码。

这意味着,如果输入给出,您不仅可以询问特定结果,还可以询问解决方案一般的方式。

但是,要实现这一点,您必须考虑一下您表示数据的方式。例如,在您的情况下,表达式中仍然是逻辑变量的任何术语都可以表示 给定数字原子应该被解释为与普通数字不同另外两个术语。这称为默认表示,因为您必须确定变量应该默认 ,并且没有办法将其含义仅限于其中一种可能的情况。

因此,我建议首先更改表示,以便符号区分这两种情况。例如,要表示您的案例中的表达式,让我们采用以下约定:

  • atoms 由包装器a/1
  • 表示
  • 数字由包装器n/1表示。
  • 并且情况已经如此,(+)/2将表示两个表达式的添加

因此,像b+10这样的默认术语现在应写为: a(b)+n(10) 。请注意使用包装器a/1n/1来说明我们正在处理哪种情况。这种表示称为 clean 。包装器是任意选择(虽然是助记),我们可以使用完全不同的包装器,例如atom/1number/1,或atm/1nmb/1。关键属性只是我们现在可以凭借其最外面的算符和arity象征性地区分不同的案例。

现在关键优势:使用这样的约定,我们可以编写例如:a(X)+n(Y)。这是早期术语的泛化。但是,它只包含了比X+Y更多的信息,因为在后一种情况下,我们已经忘记了这些变量的含义,而在前一种情况下,这种区别仍然存在。

现在,假设在表达式中使用了这个约定,它描述了不同的情况变得直截了当:

expression_result(n(N), _, _, n(N)).
expression_result(a(A), A, N, n(N)).
expression_result(a(A), Var, _, a(A)) :-
        dif(A, Var).
expression_result(X+Y, Var, Val, R) :-
        expression_result(X, Var, Val, RX),
        expression_result(Y, Var, Val, RY),
        addition(RX, RY, R).

addition(n(X), n(Y), n(Z)) :- Z #= X + Y.
addition(a(X), Y, a(X)+Y).
addition(X, a(Y), X+a(Y)).

请注意,我们现在可以使用模式匹配来区分这些案例。不再是if-then-elses,不再需要atom/1number/1测试。

您的测试用例按预期工作:

?- expression_result(a(a)+n(10), a, 1, Result).
Result = n(11) ;
false.

?- expression_result(a(a)+n(10), b, 1, Result).
Result = a(a)+n(10) ;
false.

现在关键优势:有了这样一个纯粹的程序(请参阅了解更多信息),我们也可以问“结果看起来像一般? “

?- expression_result(Expr, Var, N, R).
Expr = R, R = n(_1174) ;
Expr = a(Var),
R = n(N) ;
Expr = R, R = a(_1698),
dif(_1698, Var) ;
Expr = n(_1852)+n(_1856),
R = n(_1896),
_1852+_1856#=_1896 ;
Expr = n(_2090)+a(Var),
R = n(_2134),
_2090+N#=_2134 .

在这里,我使用了所有参数的逻辑变量,我从这个程序得到了相当一般的答案。这就是我使用约束进行声明性整数运算的原因。

因此,通过使用干净的表示法并使用上面的代码,可以很容易地解决您的直接问题。

只剩下一个非常小的挑战:也许你实际上希望使用默认表示,例如c+10(而不是a(c)+n(10))。您当前面临的任务是默认表示转换为干净的表示,例如通过谓词defaulty_clean/2。我把这作为一个简单的练习。一旦你有一个干净的表示,你可以使用上面的代码而无需更改。