Prolog-如何从涉及谓词的表达中分离原子?

时间:2019-02-06 16:19:26

标签: prolog

如果我有表达式:

x + y * (-z)

如何分隔它们以形成[x,y,z]的列表?

我的想法:

split2(X, [X]) :-
    X \= +(_,_),
   *(_,_),
   -(_).

split2(X + Y, [H|T]) :- 
    split2(X,[H]), 
    split2(Y, T).

(重复*和-)。

以某种方式,它仅适用于简单情况(涉及2个项或仅涉及一个谓词),而不适用于复杂的情况。

有人可以告诉我我的想法出了什么问题吗?

3 个答案:

答案 0 :(得分:2)

您的谓词非常混乱。首先,您正在使用X \= _+_来防止其他规则匹配;相反,您应该使用atomic(X)。然后,您要说的是_*_, -_,除了某些匿名变量存在以外,它没有特别明确地说什么吗?无论如何,由于一个或另一个原因,第一子句的其余部分都是错误的。

您的第二个子句开篇不错,但是我认为您出于特殊原因避免在这里使用append/3。在头中,您期望H是一个原子,但是在体内的第一个术语之后,您将强制H是一个单例列表。如果X = a*b怎么办?您希望split2(a*b,[a,b])能够统一。

不过,您离需要的地方并不远。这可能是您的一般模式:

split2(X, [X]) :- atomic(X).
split2(-X, Result) :- split2(X, Result).
split2(X+Y, Result) :-
    split2(X, XVars),
    split2(Y, YVars),
    append(XVars, YVars, Result).

为其他运算符继续使用模式。

答案 1 :(得分:2)

遵循使用DCG的解决方案,该解决方案不需要每个算术运算符的语法规则,并且充分利用了第一参数索引(从而避免了语法规则中的虚假选择点或难看的削减):

No symbol "NUMBER" in current context.

通话示例:

split(Expression, Atomics) :-
    Expression =.. [Functor| Args],
    phrase(split_atomics(Args, Functor), Atomics).

split_atomics([], Atomic) -->
    [Atomic].
split_atomics([Head| Tail], _) -->
    split_list([Head| Tail]).

split_list([]) -->
    [].
split_list([Head| Tail]) -->
    {Head =.. [Functor| Args]},
    split_atomics(Args, Functor),
    split_list(Tail).

答案 2 :(得分:1)

  

有人可以告诉我我的想法出了什么问题吗?

您正在做的事情太复杂了,这就是问题所在。如果您确实有一个有效的复合项作为输入,而您需要摆脱的是一系列原子子项,那么您可以尝试以下方法:

expression_atoms(E) -->
    {   compound(E),
        E =.. [_Name|Args]
    },
    !,
    expression_list_atoms(Args).
expression_atoms(E) -->
    {   atomic(E)
    },
    !,
    [E].

expression_list_atoms([E|Es]) -->
    expression_atoms(E),
    expression_list_atoms(Es).
expression_list_atoms([]) --> [].

(忍者编辑:请参阅solution by Paulo Moura,以更清晰地实现相同的想法。)

这是DCG而不是正常谓词的唯一原因是我太懒了,无法弄清楚如何正确执行附加操作。

这是一个小测试:

?- X = x + y * (-z).
X = x+y* -z.

?- X = x + y * (-z), write_canonical(X).
+(x,*(y,-(z)))
X = x+y* -z.

?- X = x + y * (-z), write_canonical(X), phrase(expression_atoms(X), Atoms).
+(x,*(y,-(z)))
X = x+y* -z,
Atoms = [x, y, z].

在上一个查询中,您可以看到从表达式中提取的原子。

如您所见,该解决方案不关心复合词的名称。这发生在清单的第3行:

E =.. [_Name|Args]

因此,您可以扔东西,它仍然可以“工作”:

?- phrase(expression_atoms(
    the(naked, truth(about(our(waitresses))), is(that(they(only(flirt, with, you))), to(get(a(better(tip('!')))))))),
    Atoms).
Atoms = [naked, waitresses, flirt, with, you, !].

如果您希望此操作因具有给定Arity的预定义操作符列表而失败,那么您将不得不在其中添加更多代码。