我最近开始学习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/2
或memberchk/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/2
和memberchk/2
恕我直言(但有趣的是,有些人可能会反驳).
归档时间: |
|
查看次数: |
10678 次 |
最近记录: |