如何在Prolog中找到集合的基数?

Jon*_*tan 3 prolog

我试图在 Prolog 中找到一个集合的基数。众所周知,一个集合不能有重复的元素。我试过这个。

cardinal([], 0).
cardinal([_|Tail], N):-
    removeRepeated(Tail, ListWithoutRepeated),
    cardinal(ListWithoutRepeated, N1),
    N is N1 + 1.

----------------------------------------------------
consult:                                            

?- cardinal([1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5], N).
   N = 6
Run Code Online (Sandbox Code Playgroud)

但正确的答案是 N = 5。显然我只计算尾部的项目,如果头部在尾部重复,则忽略。所以我尝试了这样的事情。即把头加到尾,重复上述过程。

join([], L, [L]).
join([Head|Tail], L, [Head|Tail2]):-
   join(Tail,L, Tail2).

cardinal([], 0).
cardinal([Head|Tail], N):-
    join(Tail,Head, List),
    removeRepeated(List, ListWithoutRepeated),
    cardinal(ListWithoutRepeated, N1),
    N is N1 + 1.
Run Code Online (Sandbox Code Playgroud)

但是当您查询时会生成无限循环。有人可以帮我解决这个问题吗?谁能帮我解决这个问题,我该如何编写 prolog 语句?

编辑 附件removeRepeated

removeRepeated([],[]).
removeRepeated([Head|Tail],ListWithoutRepeated):-
    member(Head,Tail),
    !,
    removeRepeated(Tail,ListWithoutRepeated).
removeRepeated([Head|Tail],[Head|ListWithoutRepeated]):-
    removeRepeated(Tail,ListWithoutRepeated).

----------------------------------------------------
consult:                                            

?- removeRepeated([1,1,1,1,2,2,2,3,3,3,4,4,4,8], N).
   N = [1, 2, 3, 4, 8]
Run Code Online (Sandbox Code Playgroud)

fal*_*lse 5

代码:

set_cardinality(Xs, N) :-
   list_nub(Xs, Ys),
   length(Ys, N).
Run Code Online (Sandbox Code Playgroud)

使用list_nub/2. 可以改进此定义的终止,因为它仅在长度Xs固定时终止。但在我们进入这个之前,让我们看看你的定义。

关系名称

尝试使用实际反映您定义的关系的名称。双方cardinal/2removeRepeated/2会留下一个这样的印象:前者是枢机主教之间的关系,而后者做一些事情。但是关系没有任何作用。好吧,他们“是”。或者,它们“相关”。但这些并不是真正充满动作的动词。

现在为您的第一个定义cardinal/2。事实上,我试着去读它。特别是,因为它包含了程序员眩晕的第一大原因——

递归

是的,这也让我很头晕。幸运的是,你的问题是关于 Prolog 的,在 Prolog 中,我们通常可以隐藏很多东西,但仍然可以获得很多洞察力。这是我最初看到的(我没有看到的东西被划掉了)。

基数([],0)。
基数([_|尾],N):-
    removeRepeated(Tail, ListWithoutRepeated) ,
     cardinal(ListWithoutRepeated, N1)N 是 N1 + 1

事实,我能应付。好的,空列表对应于零。对我来说听起来不错。但是,这条规则的头是:它写道:

N独立的列表的第一个元件的。

也就是说:对于cardinal([1,2],N)cardinal([2,2],N)你会得到非常相同的N值。这怎么可能是正确的?

removeRepeated/2list_nub/2可能是一个更相关的名称)适用于具有第一个参数的查询:

?- removeRepeated([1,2], X).
X = [1,2].

?- removeRepeated([1,2],[1,2]).
true.
Run Code Online (Sandbox Code Playgroud)

但是,它出乎意料地失败了:

?- removeRepeated([X,2],[1,2]).
false.    % not relational

?- X = 1, removeRepeated([X,2],[1,2]).
X = 1.
Run Code Online (Sandbox Code Playgroud)

因此,虽然专业化成功,但更通用的查询失败。这是一个明确的迹象,removeRepeated/2不是纯粹的关系。有关按预期工作的实现,请参阅list_nub/2