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

pyt*_*hon 3 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).
Run Code Online (Sandbox Code Playgroud)

你认为我的方法是正确的吗?

小智 6

你拥有的确实是一个"正确"的实现.执行该操作的谓词的标准名称是member/2,并且在任何Prolog中可用(在该名称下),并且一旦知道其名称就应该很容易找到.

但有些事情需要注意.首先,使用经典定义(这与Sterling和Shapiro的"Prolog的艺术"完全相同,第58页,与你的相同):

member_classic(X, [X|Xs]).
member_classic(X, [Y|Ys]) :-
    member_classic(X, Ys).
Run Code Online (Sandbox Code Playgroud)

如果您尝试编译它,您将获得单例错误.这是因为您命名的变量只在其范围内出现一次: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.
Run Code Online (Sandbox Code Playgroud)

换句话说,有了这个定义,即使很明显没有进一步的解决方案(因为它位于列表的末尾),Prolog也会留下一个选择点.避免这种情况的一种方法是使用一种称为"滞后"的技术,如SWI-Prolog库实现所示member/2.

另一件事:对于您当前的问题陈述,可能是这被认为是不良行为:

?- member_classic(a, [a,a,a]).
true ;
true ;
true ;
false.
Run Code Online (Sandbox Code Playgroud)

还有通常被称为另一个谓词member_check/2memberchk/2这不正是你所写的内容,即,成功或失败只有一次:

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

?- memberchk(a, [x,y,z]).
false.
Run Code Online (Sandbox Code Playgroud)

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

?- memberchk(X, [a,b,c]).
X = a. % no more solutions!
Run Code Online (Sandbox Code Playgroud)

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