Prolog:定义命题逻辑语句运算符并将参数添加到列表

Prolog: Define propositional logic statement operators and add arguments to list

我正在尝试定义一些运算符,将带有参数的运算符和单独的参数添加到列表中。

到目前为止,我已经定义了我将要使用的两个运算符,即 OR 和 NEGATION,但我不知道如何指定它们下一步必须执行的操作,即创建列表和添加它的运算符和参数。

:- op(400,fx,neg).
:- op(500,xfx,or).

在那之后,我不确定如何将运算符和参数添加到列表中以及如何合并所有列表。 根据手册中的联合指令,它将是这样的:

neg(X,[]) :- union([X],[neg(X)],[]).
or(X,Y,[]) :- union([X],[or(X,Y)],[]).
or(X,Y,[]) :- union([Y],[or(X,Y)],[]).

这不会发送任何错误,但是如何合并所有列表以及如何指定任何小写字母都可以用于输入。

一个输入的例子是:

neg(a or b).

预期输出:

[neg(a or b), a or b, a, b]

您 运行 了解 Prolog 的一个有趣的全局事物,即运算符真正浮出水面,即运算符只是构造项的另一种方式。

您的这些运算符定义使您能够创建术语,例如:

?- X = neg a or b.
X = neg a or b.

另一方面,赋予这些术语意义,将需要您创建另一个谓词。这是因为 Prolog 中的项不是自行归约的表达式——这就是为什么需要使用 is/2 将算术表达式归约为一个值的部分原因。即使是纯算术的东西在 Prolog 中也只是术语:

?- X = 16*3 + 4.
X = 16*3+4.

这不是 =/2 在 Prolog 中的一些特殊行为。条款就是这样制定的。减少该值需要部署另一个谓词:

?- X is 16*3+4.
X = 52.

所以你所做的似乎是假设你的 neg 运算符已经引入了一个双参数谓词来减少它,并且你的 or 运算符已经引入了一个三参数谓词来减少它.实际上,这些事情都没有发生,您的运算符声明所做的只是允许您创建像上面的 neg a or b 这样的术语。所以你仍然需要创建一个单独的谓词来评估它们,这就是你的语义进入画面的地方。因此,让我们实现一个 eval/2 谓词,将您的术语转换为您想要的结果值:

eval(neg X, [neg X|Result])   :- 
    eval(X, Result).

eval(X or Y, [X or Y|Result]) :- 
    eval(X, R1), 
    eval(Y, R2), 
    append(R1, R2, Result).

eval(X, [X]) :- atomic(X).

这里的关键思想是匹配你的操作员给你的东西,一次剥掉一层,递归调用其余的。我们的基本情况是 "atomic values",也就是说像 a.

这样的原子

这为我们提供了您正在寻找的内容:

?- eval(neg (a or b), R).
R = [neg (a or b), a or b, a, b] 

请注意,is/2 是一个运算符。您还可以通过声明运算符然后为其应用程序提供规则来定义 "does work" 的运算符。在这种情况下,这对您没有帮助,因为 negor 的示例要求您保留结构而不是丢弃它。另一方面,is/2 假定结构存在于右侧参数上并将其缩减为左侧的值。你可以做类似的事情,比如让 eval/2 成为一个运算符,在这种情况下,运算符用在 :- 的左侧,就像这样:

[Neg X|R] eval (neg X) :- R eval X.

然而,我发现这种情况很难处理,除非它迎来更清晰的情况,否则我肯定会避免它。

顺便说一句,您很可能希望将 op/3 调用中的 xfx 替换为 xfyyfx,因为像 [=33= 这样的结构] 由于运算符优先级冲突,将无法与 xfx 一起使用。使用 xfy,它将被解析为 a or (b or c),使用 yfx,它将被解析为 (a or b) or c,这可能更有帮助。而且,如果您打算 always 将您使用 neg 的内容括起来,那么您不需要为它声明一个运算符——一元运算符的目的只是为了允许您跳过括号(并控制它消耗了多少后面的内容。)

希望对您有所帮助!