3

我有以下规则:

noRepetition([]).
noRepetition([Elem|Rest]):- not(member(Elem,Rest)), !, noRepetition(Rest).

此规则用于确定列表中是否没有重复元素,并且成员规则确定特定元素是否属于列表。我的问题与此规则中的 cut 运算符有关,因为我不确定它的作用。

我已经为一个问题制定了以下跟踪?-noRepetition([a,b,b,c,d])并遇到了一个问题(可能与我对剪切运算符缺乏了解有关):

?-noRepetition([a,b,b,c,d])
Unfies with the second noRepetion rule and instantiates variables to:
noRepetition([a|b,b,c,d] :- not(member(a,[b,b,c,d])), !, noRepetition([b,b,c,d]).

现在我被卡住了,因为在这种情况下不是成员返回 true,因此剪切被证明是正确的,但是我不确定这个剪切是否会阻止程序进入 noRepetition(第三个目标)或者它是否会执行其他操作。如果它确实阻止程序进入 noRepetition,那么该规则将被评估为 true,但情况并非如此,因为列表中有重复。

4

2 回答 2

4

对你的问题。我的意见:削减是不必要的。您可能想刷新您对剪辑的作用的记忆;这是一个简短的总结。一个好的经验法则是查看晋级前的最后一个进球,并尝试看看它是否留下了选择点。如果是这样,那么它们都将被丢弃(连同本条款正文中早期目标的所有选择点),您只剩下第一个解决方案。所以我们看:

\+ member(Elem, Rest) % just another way to say not...

这什么时候可以留下选择点?如果为假\+ Goal则为真,否则为假。Goal据我所知,\+ Goal永远不会是真的不止一次,也永远不会是假的不止一次。那么为什么需要剪裁呢?在这种情况下,这是多余的,实际上什么也没做。

(我还是想知道你为什么一开始就把cut放在那里。有没有类似的谓词不使用否定member/2?)

提问者不赞成提供更好的解决方案,但至少还有两种其他方法可以解决这个问题。您甚至可以将它们混合在一起以获得以下定义:

all_dif_list(L) :-
    (   ground(L)
    ->  sort(L, S),
        length(L, N),
        length(S, N)
    ;   all_dif_list_nonground(L)
    ).

all_dif_list_nonground([]).
all_dif_list_nonground([X|Xs]) :-
    maplist(dif(X), Xs),
    all_dif_list_nonground(Xs).

如果您知道列表已完全实例化,则只需对其进行排序并比较长度即可。sort/2删除重复项,因此如果有重复项,排序列表会更短。

如果列表包含变量,那么安全的做法就是说列表中的每一对元素都是(并且永远是)不同的。

请记住,这member/2比其简单的名称和直截了当的定义所暗示的要复杂得多。member/2如果我认为我会从中受益,我可以很容易地写一篇关于行为的 1000 字文章。

于 2016-05-20T22:40:02.727 回答
0
noRepetition([]).
noRepetition([Item|Rest]) :- member(Item,Rest), !, fail.
noRepetition([_|Rest]) :- noRepetition(Rest).

注意:如果 Item 不是基础术语,结果可能会出乎意料。例如:

noRepetition([X,a,b]).

将失败...

于 2016-05-25T09:38:55.493 回答