我想在Prolog中使用DCG解析一个逻辑表达式。
逻辑术语表示为列表,例如 ['x','&&','y']
对于x ∧ y
,结果应该是解析树and(X,Y)
(X
和Y
是未分配的Prolog变量)。
我实现了它,一切都按预期工作,但我有一个问题:
我不知道如何解析变量'x'
和'y'
来获取真正的 Prolog 变量X
并为以后的真值分配Y
。
我尝试了以下规则变体:
-
v(X) --> [X].
:
这当然不起作用,它只返回and('x','y')
.
但是我可以用Prolog变量统一替换这个术语中的逻辑变量吗?我知道谓词term_to_atom
(作为类似问题的解决方案提出),但我认为它不能在这里用于实现预期的结果。 -
v(Y) --> [X], {nonvar(Y)}.
:
这确实会返回一个未绑定的变量,但当然每次都会返回一个新变量,即使逻辑变量('x','y',...)已经在术语中,所以['X','&&','X']
被评估为and(X,Y)
这也不是想要的结果。
这个问题有什么优雅或惯用的解决方案吗?
提前非常感谢!
编辑:
这个问题的背景是我正在尝试在Prolog中实现DPLL算法。我认为将逻辑术语直接解析为 Prolog 术语以方便使用 Prolog 回溯工具是很聪明的:
- 输入:一些逻辑项,例如 T =
[x,'&&',y]
- 解析后的术语:
[G_123,'&&',G_456]
(现在具有"真正的"Prolog变量) - 将 { boolean(t), boolean(f) } 中的值分配给 T 中的第一个未绑定变量。
- 简化术语。
- 。重复或回溯,直到找到分配
v
,以便耗尽v(T) = t
或搜索空间。
我对Prolog很陌生,老实说找不到更好的方法。我对更好的选择非常感兴趣!(所以我有点半个舒尔,这就是我想要的;-)非常感谢您到目前为止的支持...
诸如x
(无需编写'x'
)之类的基本项与未实例化的变量相关联。当然,这并不构成一种纯粹的关系。所以我不太清楚你是否真的想要这个。
您首先从哪里获得[x, &&, x]
列表?您可能有某种标记器。如果可能,请尝试在实际解析之前将变量名称与变量相关联。如果你坚持在解析过程中执行这种关联,你将不得不在整个语法中串接一对变量。也就是说,而不是像
power(P) --> factor(F), power_r(F, P).
你现在必须写
power(P, D0,D) --> factor(F, D0,D1), power_r(F, P, D1,D).
% ^^^^ ^^^^^ ^^^^
因为您正在将上下文引入到其他上下文无关的语法中。
解析 Prolog 文本时,会出现同样的问题。变量名称和具体变量之间的关联已在标记化期间建立。实际的解析器不必处理它。
在标记化期间,基本上有两种方法可以执行此操作:
1mo 收集列表中Name=Variable
的所有匹配项,稍后将它们统一:
v(N-V, [N-V|D],D) --> [N], {maybesometest(N)}.
unify_nvs(NVs) :-
keysort(NVs, NVs2),
uniq(NVs2).
uniq([]).
uniq([NV|NVs]) :-
head_eq(NVs, NV).
uniq(NVs).
head_eq([], _).
head_eq([N-V|_],N-V).
head_eq([N1-_|_],N2-_) :-
dif(N1,N2).
2一定要尽早使用一些显式字典来合并它们。
这个问题有点相关。
不确定你是否真的想按照你的要求去做。您可以通过保留变量关联列表来做到这一点,以便您知道何时重用变量以及何时使用新变量。
这是一个贪婪的下降解析器的例子,它将解析具有&&
和||
的表达式:
parse(Exp, Bindings, NBindings)-->
parseLeaf(LExp, Bindings, MBindings),
parse_cont(Exp, LExp, MBindings, NBindings).
parse_cont(Exp, LExp, Bindings, NBindings)-->
parse_op(Op, LExp, RExp),
{!},
parseLeaf(RExp, Bindings, MBindings),
parse_cont(Exp, Op, MBindings, NBindings).
parse_cont(Exp, Exp, Bindings, Bindings)-->[].
parse_op(and(LExp, RExp), LExp, RExp)--> ['&&'].
parse_op(or(LExp, RExp), LExp, RExp)--> ['||'].
parseLeaf(Y, Bindings, NBindings)-->
[X],
{
(member(bind(X, Var), Bindings)-> Y-NBindings=Var-Bindings ; Y-NBindings=Var-[bind(X, Var)|Bindings])
}.
它解析表达式并返回变量绑定。
示例输出:
?- phrase(parse(Exp, [], Bindings), ['x', '&&', 'y']).
Exp = and(_G683, _G696),
Bindings = [bind(y, _G696), bind(x, _G683)].
?- phrase(parse(Exp, [], Bindings), ['x', '&&', 'x']).
Exp = and(_G683, _G683),
Bindings = [bind(x, _G683)].
?- phrase(parse(Exp, [], Bindings), ['x', '&&', 'y', '&&', 'x', '||', 'z']).
Exp = or(and(and(_G839, _G852), _G839), _G879),
Bindings = [bind(z, _G879), bind(y, _G852), bind(x, _G839)].