我想要一个谓词来判断一个特定的原子(比如x
(是否出现在复合项中,无论嵌套得多么深。
我试图阅读有关 https://www.swi-prolog.org/pldoc/man?section=manipterm 给出的谓词的信息。我认为这将涉及使用functor/3
和../2
回避地走复合术语。有没有更简单的方法,或者一些库可以做到这一点?
Carlo 的优雅答案适用于 SWI-Prolog,但不可移植,因为 ISO Prologarg/3
谓词的标准规范(大多数 Prolog 系统实现(要求其第一个参数绑定到整数,防止将其用作复合项参数的可反向生成器。更便携的替代方案是:
haystack_needle(H, N) :-
H == N.
haystack_needle(H, N) :-
functor(H, _, A),
between(1, A, I),
arg(I, H, A),
haystack_needle(A, N).
ISO Prolog 标准中未指定between/3
谓词,但它是事实上的标准谓词,通常作为内置谓词或库谓词提供。
忽略循环项,我会使用 ==/2,化合物/1 和 arg/3
haystack_needle(H,N) :- H==N.
haystack_needle(H,N) :- compound(H),arg(_,H,A),haystack_needle(A,N).
haystack_needle/2 将成功多次,然后允许计数发生次数:
?- aggregate(count, haystack_needle(t(a,x,b,[x,x,x]),x), C).
C = 4.
注意,针不需要是原子...
您可以使用 once/1 来判断针是否出现在大海捞针中:
?- once(haystack_needle(t(a,x,b,[x,x,x]),x)).
true.
?- once(haystack_needle(t(a,x,b,[x,x,x]),z)).
false.
正如Paulo所指出的,arg/3无法在符合ISO标准的Prologs中适当地发挥作用。 一个可移植的替代方案(交换参数,除了避免混淆之外没有其他目的(可能是
needle_haystack(N,H) :- N==H.
needle_haystack(N,H) :- H=..[_|As],member(A,As),needle_haystack(N,A).
当然,如果会员/2 可用:)