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" 的运算符。在这种情况下,这对您没有帮助,因为 neg
和 or
的示例要求您保留结构而不是丢弃它。另一方面,is/2
假定结构存在于右侧参数上并将其缩减为左侧的值。你可以做类似的事情,比如让 eval/2
成为一个运算符,在这种情况下,运算符用在 :-
的左侧,就像这样:
[Neg X|R] eval (neg X) :- R eval X.
然而,我发现这种情况很难处理,除非它迎来更清晰的情况,否则我肯定会避免它。
顺便说一句,您很可能希望将 op/3
调用中的 xfx
替换为 xfy
或 yfx
,因为像 [=33= 这样的结构] 由于运算符优先级冲突,将无法与 xfx
一起使用。使用 xfy
,它将被解析为 a or (b or c)
,使用 yfx
,它将被解析为 (a or b) or c
,这可能更有帮助。而且,如果您打算 always 将您使用 neg
的内容括起来,那么您不需要为它声明一个运算符——一元运算符的目的只是为了允许您跳过括号(并控制它消耗了多少后面的内容。)
希望对您有所帮助!
我正在尝试定义一些运算符,将带有参数的运算符和单独的参数添加到列表中。
到目前为止,我已经定义了我将要使用的两个运算符,即 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" 的运算符。在这种情况下,这对您没有帮助,因为 neg
和 or
的示例要求您保留结构而不是丢弃它。另一方面,is/2
假定结构存在于右侧参数上并将其缩减为左侧的值。你可以做类似的事情,比如让 eval/2
成为一个运算符,在这种情况下,运算符用在 :-
的左侧,就像这样:
[Neg X|R] eval (neg X) :- R eval X.
然而,我发现这种情况很难处理,除非它迎来更清晰的情况,否则我肯定会避免它。
顺便说一句,您很可能希望将 op/3
调用中的 xfx
替换为 xfy
或 yfx
,因为像 [=33= 这样的结构] 由于运算符优先级冲突,将无法与 xfx
一起使用。使用 xfy
,它将被解析为 a or (b or c)
,使用 yfx
,它将被解析为 (a or b) or c
,这可能更有帮助。而且,如果您打算 always 将您使用 neg
的内容括起来,那么您不需要为它声明一个运算符——一元运算符的目的只是为了允许您跳过括号(并控制它消耗了多少后面的内容。)
希望对您有所帮助!