为什么结果列表的末尾不是[]?

时间:2019-05-22 06:04:03

标签: prolog

  

我试图输出仅包含唯一元素的列表。但是结果并不完美。

list_concatenation([],L,L).
list_concatenation([X1|L1],L2,[X1|L3]) :-
    list_concatenation(L1,L2,L3).

list_member(X, [X|_]).
list_member(X, [_|TAIL]) :- list_member(X,TAIL),!.

toset([],_).
toset([X|TAIL],SET):-
    list_member(X,SET),
    toset(TAIL,SET).
toset([X|TAIL],SET):-
    \+ list_member(X,SET),
    list_concatenation([X],SET,NEWSET),
    toset(TAIL,NEWSET).

例如: ?- toset([1,1,2,3],X).

  

结果应该是'X = [1, 2, 3]',但现在是'X = [1, 2, 3|_16998]'

1 个答案:

答案 0 :(得分:1)

您实际上以错误的方式实现了toset/2。您实际上在这里使用list_member/2将元素添加到列表中。确实,如果您使用自由变量,则会得到:

?- list_member(2, L).
L = [2|_3616] ;
L = [_3614, 2|_3622].

list_member/2本身也没有正确实现。此处的剪切(!阻止保持屈服值。因此,您应该删除剪切:

list_member(X, [X|_]).
list_member(X, [_|Tail]) :-
    list_member(X,Tail).

因此,这可以产生其中2是成员的所有可能的列表:

?- list_member(2, L).
L = [2|_3412] ;
L = [_3410, 2|_3418] ;
L = [_3410, _3416, 2|_3424] ;
L = [_3410, _3416, _3422, 2|_3430] ;
...

但是现在问题仍然存在:您不应该在此处使用list_member/2将元素添加到列表中,可以在此处使用累加器来跟踪已经产生的元素,然后最终返回该累加器,例如:

toset(L, S) :-
    toset(L, [], S).
toset([], A, S):-
    reverse(A, S).
toset([H|T], A, L) :-
    (  member_list(H, A)
    -> toset(T, [H|A], L)
    ;  toset(T, A, L)
    ).

因此,我们将这些值始终放在累加器的前面,最后reverse/2 [swi-doc]累加器,然后将其返回。

相关问题