пролог удалить все не работает

Я пытался выяснить проблему, но безуспешно Не могли бы вы сказать мне, что не так?

% using accumulator
deleteall(X,Y,Zs) :- deleteall(X,Y, [], Zs).
deleteall(X, [], Zs, Zs).
deleteall(X, [X|Xs], Xs, V).
deleteall(X, [Y|Xs], [Y|Zs], V) :- deleteall(X, Xs, Zs,V).

person Peter Dubec    schedule 28.05.2012    source источник


Ответы (3)


Для чистого решения рассмотрите этот ответ, обратите внимание на другой порядок аргументов.

Но на самом деле ваш вопрос был таков: что не так с вашим решением?

Есть способ ответить на этот вопрос уникальным для Пролога образом. В других языках программирования вам пришлось бы придумывать осмысленные тестовые примеры. Затем вы должны использовать такие тестовые примеры, чтобы увидеть, работает ли ваша реализация. Конечно, это возможно и в Прологе.

Но подумайте о фактической стоимости расчета этих тестовых случаев! Вы должны были бы понять всю связь во всех ее деталях. Вам нужно было бы мысленно представить весь мелкий шрифт о структурах данных. Это довольно интеллектуальное усилие. Ваш пример очень прост, так что усилия кажутся мелочными. Но представьте, что здесь и там добавляются дополнительные детали.

Итак, как мы можем вычислить тестовый пример для предиката, не понимая фактического отношения?

Просто возьмите самый общий запрос. То есть цель с различными переменными во всех аргументах. Для вашего примера это будет deleteall(X, Xs, Ys). Теперь наша работа выполнена, и мы можем позволить Прологу заполнить пробелы.

?- deleteall(X,Xs,Ys).
Xs = Ys, Ys = [] ;
Xs = [X] ;
false.

С вашим определением мы получаем два ответа. Первый ответ содержит решения для Xs, являющегося пустым списком []. Второй ответ содержит решения для Xs, являющегося списком из одного элемента. И это все, что описывает ваше отношение.

А как насчет списков, содержащих два или даже больше элементов? Для них нет решений. Так что ваше определение слишком конкретно в этом отношении.

И второй ответ верен для всех Ys. Например. также deleteall(1,[1],[2,3]) выполняется в соответствии с вашим определением. Еще хуже: deleteall(1,[1],[1]). Никакого удаления. Так что ваше определение здесь слишком общее.


Где подвох во всем этом? Ну, вы должны писать чистые, монотонные программы. То есть нечистые встроенные функции, такие как !/0, (\+)/1, (\=)/2, (\==)/2, а также встроенные функции с побочными эффектами не должны использоваться (или использоваться с особой осторожностью).

person false    schedule 29.05.2012

Одноэлементные переменные всегда подозрительны, и в вашем случае, что означает V в deleteall(X, [X|Xs], Xs, V).?

Кроме того, я не понимаю, почему вы используете аккумулятор.

Вам назначено реверсировать не удаленные элементы? В противном случае, вот удаление всего, что работает...

deleteall(_, [], []).
deleteall(X, [X|Xs], Zs) :- !, deleteall(X, Xs, Zs).
deleteall(X, [Z|Xs], [Z|Zs]) :- deleteall(X, Xs, Zs).

контрольная работа:

?- deleteall(2,[1,2,3,54,2,1,4,2],X).
X = [1, 3, 54, 1, 4] ;
false.
person CapelliC    schedule 28.05.2012

Из вашего кода кажется, что вы хотите удалить всю семантику, основанную на унификации (альтернативой может быть удаление только равных терминов с использованием (==)/2). Все ли элементы списка (и элементы, которые вы хотите удалить) всегда заземлены? В противном случае ваш код может дать сбой всякий раз, когда элемент, который вы хотите удалить, создается частично и получает дальнейшее создание экземпляра при объединении с одним из элементов списка. Вы можете решить эту проблему, используя, например. двойное отрицание в теле вместо объединения головы. Как уже заметил "chac", вы также оставляете позади точки выбора. Использование разреза или if-then-else решает эту проблему. Еще один способ улучшить ваш код — переместить список к первому аргументу, позволяя индексации Prolog по первому аргументу повысить производительность (предполагая, конечно, что вызовы предиката будут иметь экземпляр первого аргумента). Следует определению в следующих строках:

delete_all([], _, []).
delete_all([X|Xs], Y, Zs) :-
    (   \+ X \= Y ->
        delete_all(Xs, Y, Zs)
    ;   Zs = [X|Zs0],
        delete_all(Xs, Y, Zs0)
    ).
person Paulo Moura    schedule 28.05.2012