使用Prolog中的cut来定义once_member/2函数

Pet*_*ton 8 prolog prolog-cut

免责声明:这是我自己的非正式和非评估课程.我自己尝试过,失败了,现在正在寻找一些指导.

我正在尝试实现一个成员/ 2函数的版本,它只返回一次列表的成员.

例如:

| ?- member(X, [1,2,3,1]).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
X = 1 ? ;
Run Code Online (Sandbox Code Playgroud)

我希望它只能打印出最多一次的每个数字.

| ?- once_member(X, [1,2,3,1]).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
no
Run Code Online (Sandbox Code Playgroud)

我们被告知用切割'!'做到这一点 操作员,但我已经查看了我的课程笔记和更多的在线,但仍然不能让它点击我的头!

到目前为止,我已设法得到:

once_member(E, [E | L]) :- !.
once_member(E, [_, L]) :-
    once_member(E, L).
Run Code Online (Sandbox Code Playgroud)

哪个返回1然后没有别的,我觉得我的切割位置错误并阻止了每个可能的匹配的回溯但我真的不确定下一步该去哪里.

我查看了我的课程笔记,并查看了:http://www.cs.ubbcluj.ro/~csatol/log_funk/prolog/slides/5-cuts.pdfProlog编程(Google Books)

关于如何在逻辑上应用切割的指导将是最有用的,但答案可能有助于我自己解决这个问题.

我们也被告知要做另一种使用'\ +'否定失败的方法,但希望这一切可能更简单一旦削减了我?

har*_*ath 0

下面是一种方法,它使用了once_member/2定义中的剪切以及经典的member/2谓词:

once_member(X,[H|T]) :-
    member(H,T),
    !,
    once_member(X,T).
once_member(H,[H|_]).
once_member(X,[_|T]) :-
    once_member(X,T).
Run Code Online (Sandbox Code Playgroud)

应用到上面的例子:

?- once_member(X,[1,2,3,1]).

X = 2 ;

X = 3 ;

X = 1 ;
no
Run Code Online (Sandbox Code Playgroud)

注意:尽管出现了奇怪的三个子句定义,once_member/2仍然符合最后调用/尾递归优化的条件,因为剪切放置在其第一次自调用之前。