定义规则以确定列表是否包含给定成员

时间:2015-11-25 07:41:39

标签: list prolog

我最近开始学习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).

您认为我的方法是否正确?

2 个答案:

答案 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/2memberchk/2的谓词,它完全完全你所写的内容,即成功或失败一次:

?- memberchk(a, [a,a,a]).
true.

?- memberchk(a, [x,y,z]).
false.

但是,当第一个参数是可能不合需要的变量时,它具有以下行为:

?- memberchk(X, [a,b,c]).
X = a. % no more solutions!

member/2memberchk/2恕我直言的有效用途(但有趣的是,有些人可能会反驳)。

答案 1 :(得分:4)

是的,您的解决方案是正确的,可以向所有方向发挥作用。尼斯!

注意:

  1. 您的解决方案实际上比任务要求的更为通用。这是件好事!在我看来,这项任务措辞严厉。首先,第一个子句不是规则,而是事实。最好将这样的任务表达为:“编写一个真正的程序如果一个术语出现在列表中。”这留下了一个好的解决方案自动解决的其他用例,例如生成解决方案。
  2. 这个常见谓词广为人知member/2。就像您的解决方案一样,它也适用于所有方向。试试例如?- member(E, Ls).
  3. 谓词的名称可能更好。 Prolog的一个好的命名约定清楚地说明了每个参数的含义。例如:element_list/2,并从那里开始。