如果我有表达式:
x + y * (-z)
如何分隔它们以形成[x,y,z]
的列表?
我的想法:
split2(X, [X]) :-
X \= +(_,_),
*(_,_),
-(_).
split2(X + Y, [H|T]) :-
split2(X,[H]),
split2(Y, T).
(重复*和-)。
以某种方式,它仅适用于简单情况(涉及2个项或仅涉及一个谓词),而不适用于复杂的情况。
有人可以告诉我我的想法出了什么问题吗?
答案 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的预定义操作符列表而失败,那么您将不得不在其中添加更多代码。