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

时间:2019-10-13 19:25:19

标签: list prolog operators

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

到目前为止,我已经定义了我要使用的两个运算符,即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]

1 个答案:

答案 0 :(得分:0)

您正在碰到关于Prolog的有趣的全局性问题,操作员真正将其浮出水面,这就是操作员只是构造术语的另一种方式。

这些运算符定义使您可以创建术语,例如:

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

另一方面,赋予这些术语含义则需要您创建另一个谓词。这是因为Prolog中的术语不是单独减少的表达式-这部分是为什么您需要使用is/2将算术表达式减少为值的部分原因。甚至纯算术的东西也只是Prolog中的术语:

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

这不是Prolog中=/2的某些特殊行为。这就是条款的制定方式。降低价值需要部署另一个谓词:

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

此处的关键思想是匹配操作员给您的内容,并一次剥离一层,然后递归调用其余部分。我们的基本情况是“原子值”,也就是说像a这样的原子。

这为我们提供了您想要的东西:

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

请注意,is/2是运算符。您还可以通过声明运算符,然后为其应用程序提供规则来定义一个“起作用”的运算符。在这种情况下,这对您无济于事,因为您的negor示例要求您保留结构而不是丢弃它。另一方面,is/2假定该结构存在于右侧参数上,并将其简化为左侧的值。您可以执行类似的操作,例如说eval/2作为运算符,在这种情况下,该运算符用于:-的左侧,如下所示:

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

但是,我发现这种处理方式很难处理,除非可以带来更多的清晰度,否则肯定会避免。

顺便说一句,您很可能希望将xfx调用中的op/3替换为xfyyfx,因为类似a or b or c的结构会由于操作员优先级冲突,因此无法与xfx配合使用。使用xfy,它将被解析为a or (b or c),使用yfx,它将被解析为(a or b) or c,这可能会更有用。而且,如果您打算始终用 括起neg所用的内容,则无需为此声明一个运算符-一元运算符的目的只是允许您跳过括号(并控制其消耗了多少)。

希望这会有所帮助!