我正在尝试定义一些运算符,以将带有参数和唯一参数的运算符添加到列表中。
到目前为止,我已经定义了我要使用的两个运算符,即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]
答案 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
是运算符。您还可以通过声明运算符,然后为其应用程序提供规则来定义一个“起作用”的运算符。在这种情况下,这对您无济于事,因为您的neg
和or
示例要求您保留结构而不是丢弃它。另一方面,is/2
假定该结构存在于右侧参数上,并将其简化为左侧的值。您可以执行类似的操作,例如说eval/2
作为运算符,在这种情况下,该运算符用于:-
的左侧,如下所示:
[Neg X|R] eval (neg X) :- R eval X.
但是,我发现这种处理方式很难处理,除非可以带来更多的清晰度,否则肯定会避免。
顺便说一句,您很可能希望将xfx
调用中的op/3
替换为xfy
或yfx
,因为类似a or b or c
的结构会由于操作员优先级冲突,因此无法与xfx
配合使用。使用xfy
,它将被解析为a or (b or c)
,使用yfx
,它将被解析为(a or b) or c
,这可能会更有用。而且,如果您打算始终用 括起neg
所用的内容,则无需为此声明一个运算符-一元运算符的目的只是允许您跳过括号(并控制其消耗了多少)。
希望这会有所帮助!