Prolog - 替换和评估

Prolog - subsitution and evaluation

你好编程的好人。

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

这是我到目前为止完成的代码。

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).

以加操作为例:

arithmeticAdd_expression(Expression, Variable, Value, Result)

?- arithmeticAdd_expression(a+10, a, 1, Result).
?- Result = 11;
?- Result = a + 10.

?- arithmeticAdd_expression(a+10, b, 1, Result).
?- Result = a + 10.

我想实现的是 如果 Expression 中的原子只能由给定的 Variable 和 value 替换,则 Result 只是数字,如上例所示 (Result = 11)。否则,结果只是表达式本身。我的代码问题就在那里,我就是能弄明白。那么,请有人可以帮助我吗?谢谢。

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

这意味着如果输入给定,您不仅可以询问特定结果,还可以询问解决方案一般[=88] =].

但是,要使其发挥作用,您必须考虑一下表示数据的方式。例如,在您的情况下,表达式中仍然是逻辑变量的任何术语可能表示 给定数字 应该是的原子与普通数字 不同的解释是另外两个术语的加法。这被称为 defaulty 表示,因为您必须决定一个变量在默认情况下 应该表示什么,并且没有办法将其含义限制为仅可能的情况之一。

因此,我建议首先更改表示形式,以便您可以象征性地区分这两种情况。例如,为了在您的案例中表示表达式,让我们采用以下约定:

  • atoms 由包装器 a/1
  • 表示
  • 数字 由包装器 n/1.
  • 表示
  • 和已经存在的情况一样,(+)/2 应表示两个表达式的 加法

所以,像 b+10 这样的默认术语现在应该写成:a(b)+n(10)。请注意包装器 a/1n/1 的使用,以明确我们正在处理哪种情况。这种表示称为 clean。包装器是任意选择的(尽管是助记符),我们可以使用完全不同的包装器,例如 atom/1number/1,或 atm/1nmb/1。关键 属性 只是我们现在可以象征性地 区分 不同的情况,凭借它们的最外层函子和元数。

现在关键优势:使用这样的约定,我们可以写成例如: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.

现在关键优势:有了这么纯的程序(请看了解更多),我们还可以问"What do results look like in general?"

?- 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。我把它留作一个简单的练习。一旦你有了一个干净的表示,你就可以使用上面的代码而无需更改。