2016-11-16 9 views
1

Я довольно новичок в прологе, и сейчас я читаю книгу, которая дает мне примеры практики для кода. Он поручил мне удалить дубликаты.Удаление дубликатов в прологе

Примечание: я прочитал другие stackoverflows, и я понимаю, как удалить дубликаты, но я не понимаю, почему мой код не работает. (Я выбрал другой подход к другим потокам stackoverflow)

Я создал предикат is_member, который, как я считаю, отлично работает.

is_member(X, [Head,Tail]):- 
    X == Head; 
    is_member(X, Tail). 

И тогда мое remove_duplicates предикат

remove_duplicates([Head|Tail], Without):- 
    is_member(Head, Tail), 
    remove_duplicates(Tail, Without); 
    remove_duplicates(Tail, Head). 

В моей голове это имеет смысл, он проверяет, является ли глава является членом хвоста, и если он есть, он не добавляет его к Без списка,

еще это делает.

Очевидно, я что-то отсутствует тривиальное здесь,

Заранее спасибо

ответ

3

Давайте упростить задачу немного по первому рассмотрении is_member/2.

Вы пишете как:

 
is_member(X, [Head,Tail]):- 
    X == Head; 
    is_member(X, Tail). 

Рассмотрим, как легко это неправильно это как:

 
is_member(X, [Head,Tail]):- 
    X == Head, 
    is_member(X, Tail). 

Упражнение: Что я могу изменить?

По этой причине я рекомендую макет, как следующее:

 
is_member(X, [Head,Tail]):- 
     ( X == Head 
     ; is_member(X, Tail) 
     ). 

Теперь, на несколько тестов!

Во-первых, это всегда хорошая идея опубликовать наиболее общий запрос. Это просто спрашивает: Есть ли какие-либо решения?

 
?- is_member(E, Ls). 
nontermination 

Это не хороший знак!

Итак, давайте попробуем несколько конкретных корпусов. Например, является a членом пустого списка?

 
?- is_member(a, []). 
false. 

Это хорошо! Это то, чего мы ожидали.

В таком случае a является членом списка [a]?

 
?- is_member(a, [a]). 
false. 

Это определенно неправильно!

Я рекомендую вам начать с этого времени, а затем перейти к более сложным определениям. Подойдите к нему на систематической основе:

  1. Запишите то, что должен держать.
  2. Попробуйте наиболее общий запрос, чтобы узнать, можете ли вы получить ответы от своей программы.
  3. Пробег конкретные тестовые примеры.
  4. Подумайте, что на самом деле предикат означает: Вы можете использовать предикат в нескольких направлениях, и во многих из этих случаев способ, которым вы описали предикат, не имеет смысла. Например, и список, и элемент уже могут быть , указанными, и в этом случае ничего не нужно «добавлять» или «удалять».

Чтобы найти причины неожиданного сбоя в программе, используйте , например, используя следующее определение обобщать далеко цели:

:- op(920,fy, *). 
*_.

Теперь вы можете написать:

 
is_member(X, [Head,Tail]):- 
     ( *X == Head 
     ; *is_member(X, Tail) 
     ). 

, который является массивного обобщения вашей оригинальной программы, а на самом деле декларативно эквивалент   к:

 
is_member(X, [Head,Tail]) :- true. 

Тестовый пример выше все еще не с этим фрагментом, который показывает, что программа еще слишком   конкретных:

 
?- is_member(a, [a]). 
false. 
+0

Блестящий ответ, спасибо Я отвечу на совет – user3667111

+0

Также считаю, что исправил ошибку. С: 'is_member (X, [Голова | _]): - \t X == Голова. ' – user3667111

+0

Это фиксирует конкретный тестовый пример' is_member (a, [a]) ', да. Однако попробуйте * небольшое * ** обобщение ** тестового примера: '? - is_member (a, [X]).' Это все еще ** не работает **. В целом я могу только рекомендовать ** избегать ** немонотонных предикатов, таких как '(==)/2'. Их можно безопасно использовать только в особых ситуациях и давать ** неправильные ** ответы в более общих случаях. Чтобы выразить, что два слагаемых ** равны **, используйте '(=)/2'. Он корректно работает во всех * направлениях. – mat

 Смежные вопросы

  • Нет связанных вопросов^_^