Заполнить список только одним вхождением нескольких элементов списка

Я новичок в Прологе, и я пытаюсь его понять.

Я начал с простой программы, которая должна:

  • check if an element is contained in the rest of the list
    • if FALSE do nothing
    • если TRUE, добавьте его во второй список. (во второй список должно быть добавлено только одно вхождение символа).

Несколько примеров с ожидаемыми результатами:

?- occ([a,b,c,a,a,b,e,f,g], Y).
Y = [a,b].

?- occ([a,a,a,a,a], Y).
Y = [a].

?- occ([a,b,c,d,e,f,g], Y).
Y = [].

Вот код, который я написал, но у меня есть некоторые проблемы (он всегда возвращает true).

occ([],[]).
occ([],_Y).
occ([X|Xs],[X|Y]) :-
   occ(Xs,Y),
   member(X,Xs),
   not(member(X,Y)),
   !.
occ([_X|_Xs],_Y).

Я попытался использовать отладчик и обнаружил, что not(member(X,Y)) всегда false, а в разделе привязки есть только X и Xs и никогда Y. Любой совет очень ценится! Спасибо.

ОБНОВЛЕНИЕ

Я думаю, что решил это, вот код:

occ([],[]).
occ([X|Xs],[X|Y]) :-
   occ(Xs,Y),
   member(X,Xs),
   not(member(X,Y)),
   !.
occ([_X|_Xs],[]).

Но я не совсем уверен, почему это работает сейчас... в 3-м occ я поменял _Y на [].. Но почему это меняет результаты?


person Marcx    schedule 26.11.2015    source источник
comment
Ваш предикат всегда возвращает true, потому что у вас есть два предложения, которые вместе будут принимать любые аргументы списка и выполняться успешно. occ([], _Y). всегда будет успешным, независимо от второго аргумента, если первый аргумент — это пустой список []. И occ([_X|_Y], _Y). всегда будет успешным, если первый аргумент представляет собой список хотя бы из одного элемента, и независимо от того, какой второй аргумент. Что вы хотите сделать, так это убедиться, что каждое предложение имеет смысл само по себе, поскольку выражает действительное правило относительно своих аргументов.   -  person lurker    schedule 26.11.2015
comment
Я попытался изменить свой код, но не смог добиться того, чего ожидал... не могли бы вы помочь мне еще немного? Я думаю, что я что-то упускаю..   -  person Marcx    schedule 26.11.2015
comment
Это может помочь, если вы отредактируете свой вопрос с последними изменениями, чтобы узнать, каковы ваши текущие мысли.   -  person lurker    schedule 26.11.2015
comment
Я обновил свой вопрос и, вероятно, решил его ... хотя я действительно не понял, почему он работает сейчас ... не могли бы вы лучше объяснить мне это, пожалуйста? edit2: я не уверен, что это всегда работает :\   -  person Marcx    schedule 26.11.2015
comment
Я думаю, что это все еще проблема. Ваше третье правило в основном говорит, что любой непустой список должен давать пустой список, что не должно быть правдой. Можете ли вы объяснить, почему у вас есть это правило? Любое правило, которое у вас есть, вы должны уметь описать словами. Это то, что поможет вам понять ваше решение. Ваше первое правило гласит: Результатом пустого списка является пустой список, что, безусловно, имеет смысл. Ваше второе правило гласит: [X|Y] является результатом [X|Xs], если Y является результатом Xs, а X является элементом Xs, а X не является элементом Y.   -  person lurker    schedule 26.11.2015


Ответы (1)


В этом ответе мы используем meta-predicate tpartition/4 в сочетании с if_/3 и (=)/3.

Мы определяем list_duplicateset/2 следующим образом:

list_duplicateset([], []).
list_duplicateset([E|Xs0], Ys0) :-
   tpartition(=(E), Xs0, Es, Xs),
   if_(Es=[],
       Ys0 = Ys,
       Ys0 = [E|Ys]),
   list_duplicateset(Xs, Ys).

Во-первых, мы запускаем пример запроса, взятый из этот ответ на аналогичный вопрос:

?- list_duplicateset([1,2,2,3,4,5,7,6,7], Xs). 
Xs = [2,7].

Затем давайте запустим запросы, которые дал OP:

?- list_duplicateset([a,b,c,a,a,b,e,f,g], Xs).
Xs = [a, b].

?- list_duplicateset([a,a,a,a,a], Xs).
Xs = [a].

?- list_duplicateset([a,b,c,d,e,f,g], Xs).
Xs = [].

Обратите внимание, что все запросы, представленные выше, дают ожидаемые ответы и детерминировано успешно.

person repeat    schedule 26.11.2015