Prolog 序言:从命题公式中获得唯一原子

Prolog 序言:从命题公式中获得唯一原子,prolog,Prolog,我可以很容易地编写一个谓词,从Prolog中给定的列表中获取唯一的元素 no_doubles( [], [] ). no_doubles( [H|T], F ) :- member( H, T ), no_doubles( T, F ). no_doubles( [H|T], [H|F] ) :- \+ member( H, T ), no_doubles( T, F ). 然而,除了正常列表之外,你怎么能做同样的事情,即不是像[a,b,c…]这样的东西?在我的例子中,我想为一个命题公

我可以很容易地编写一个谓词,从Prolog中给定的列表中获取唯一的元素

no_doubles( [], [] ).
no_doubles( [H|T], F ) :-
 member( H, T ),
 no_doubles( T, F ).
no_doubles( [H|T], [H|F] ) :-
 \+ member( H, T ),
 no_doubles( T, F ).
然而,除了正常列表之外,你怎么能做同样的事情,即不是像[a,b,c…]这样的东西?在我的例子中,我想为一个命题公式提取唯一的原子,例如唯一的_原子(和(x,和(x,y),z),[x,y,z])。他很满意。您是否像我的no_doubles示例中那样使用递归,但对于这样的公式

欢迎任何想法:)。谢谢

命题公式:

get_atoms(X,[X]) :-
    atom(X).
get_atoms(and(P,Q),Atoms) :-
    get_atoms(P,Left),
    get_atoms(Q,Right),
    append(Left,Right,Atoms).
如有必要,使用差异列表进行优化

unique_atoms(P,UniqueAtoms) :- get_atoms(P,Atoms), sort(Atoms,UniqueAtoms).

一种更直接的方法是使用。

因此,您需要处理一个通用术语(即树结构),并获得其原子叶节点的列表,无重复项。结果列表是否必须有特定的顺序(例如从左到右的深度优先),或者这并不重要

如果您可以选择在公式中使用变量而不是原子,那么您可以使用(SWI Prolog)内置的
term_variables/2
,例如

?- term_variables(and(X, and(X, Y), Z), Vars).
Vars = [X, Y, Z].
否则,您必须使用类似于以下内容的解决方案:

term_atoms(Term, AtomSet) :-
    term_to_atomlist(Term, AtomList),
    list_to_set(AtomList, AtomSet).


term_to_atomlist(Atom, [Atom]) :-
    atom(Atom),
    !.

term_to_atomlist(Term, AtomList) :-
    compound(Term),
    Term =.. [_ | SubTerms],
    terms_to_atomlist(SubTerms, AtomList).


terms_to_atomlist([], []).

terms_to_atomlist([Term | Terms], AtomList) :-
    term_to_atomlist(Term, AtomList1),
    terms_to_atomlist(Terms, AtomList2),
    append(AtomList1, AtomList2, AtomList).
用法示例:

?- term_atoms(f(x^a1+a3*a3/a4)='P'-l, Atoms).
Atoms = [x, a1, a3, a4, 'P', l].

您可能希望扩展它以处理叶节点中的数字和变量。

谢谢larsmans,您的get_atoms谓词让我大致了解了我应该做什么,我现在已经解决了我的问题,谢谢:)。我还将查看你发布的sets链接,谢谢。
?- term_atoms(f(x^a1+a3*a3/a4)='P'-l, Atoms).
Atoms = [x, a1, a3, a4, 'P', l].