我最近开始学习prolog,并面临这个问题的问题:
定义规则以确定列表是否包含给定成员。
我搜遍了所有堆栈溢出,以获得一些链接,以更好地理解这个问题,并为它编写解决方案,但找不到任何东西。你们中的任何人都可以建议解决这个特殊问题吗?
我的方法:
Iterative over the list and see if your member matches with head:
on(Item,[Item|Rest]). /* is my target item on the list */
on(Item,[DisregardHead|Tail]):-
on(Item,Tail).
您认为我的方法是否正确?
答案 0 :(得分:6)
你所拥有的确是一个"正确的"实现。执行该操作的谓词的标准名称是member/2
,并且在任何Prolog中都可用(在该名称下),并且一旦知道其名称就应该很容易找到。
但有些事情需要注意。首先,使用经典定义(这与#34; Prolog的艺术"由Sterling和Shapiro编写,第58页,与您的相同):
member_classic(X, [X|Xs]).
member_classic(X, [Y|Ys]) :-
member_classic(X, Ys).
如果您尝试编译它,您将获得单例错误。这是因为您命名的变量只在其范围内出现一次:第一个子句中的Xs
和第二个中的Y
。除此之外,这是程序的作用:
?- member_classic(c, [a,b,c,x]).
true ;
false.
?- member_classic(c, [c]).
true ;
false.
?- member_classic(X, [a,b,c]).
X = a ;
X = b ;
X = c ;
false.
换句话说,有了这个定义,即使很明显没有进一步的解决方案(因为它位于列表的末尾),Prolog也会留下一个选择点。避免这种情况的一种方法是使用一种称为"滞后"的技术,如SWI-Prolog library implementation of member/2
所示。
另一件事:对于您当前的问题陈述,可能会将此视为不良行为:
?- member_classic(a, [a,a,a]).
true ;
true ;
true ;
false.
还有一个通常称为member_check/2
或memberchk/2
的谓词,它完全完全你所写的内容,即成功或失败一次:
?- memberchk(a, [a,a,a]).
true.
?- memberchk(a, [x,y,z]).
false.
但是,当第一个参数是可能不合需要的变量时,它具有以下行为:
?- memberchk(X, [a,b,c]).
X = a. % no more solutions!
member/2
和memberchk/2
恕我直言的有效用途(但有趣的是,有些人可能会反驳)。
答案 1 :(得分:4)
是的,您的解决方案是正确的,可以向所有方向发挥作用。尼斯!
注意:
member/2
。就像您的解决方案一样,它也适用于所有方向。试试例如?- member(E, Ls).
element_list/2
,并从那里开始。