Пролог: как написать (и использовать) функцию, которая перечисляет все перестановки списка?
Я нашел такой пример наивного рода, написанный в прологе, и я пытаюсь понять это:
naive_sort(List,Sorted):-perm(List,Sorted),is_sorted(Sorted).
is_sorted([]).
is_sorted([_]).
is_sorted([X,Y|T]):-X=<Y,is_sorted([Y|T]).
perm(List,[H|Perm]):-delete(H,List,Rest),perm(Rest,Perm).
perm([],[]).
delete(X,[X|T],T).
delete(X,[H|T],[H|NT]):-delete(X,T,NT).
Вызов Naive_sort работает правильно, но я просто не могу понять, почему. Основная проблема - перестановка. Когда он вызывается неявно, он всегда возвращает только одно значение. Как тогда возможно, что при вызове функции naive_sort проверяются все перестановки? Также, как я могу изменить функцию perm для записи всех перестановок?
3 ответа
Это действительно наивный вид - он пересекает дерево всех возможных перестановок, пока, к счастью, не находит отсортированный. Это сложность O(n!) Я предполагаю:>
Насчет функции перестановки - она работает "в обратном направлении" - обратите внимание, что определение выводит голову из результата. Если вы измените свою точку зрения, вы заметите, что вместо удаления она фактически вставляет значения, работая в обратном направлении. Поскольку алгоритм работает в обратном направлении, следовательно, H
Может быть выбрано все, что позволит создать результат, следовательно, любое неиспользуемое значение из List.
В основном алгоритм перестановки переводится в следующую процедурную реализацию:
- выбрать предмет из списка
- положить его на перед сортировкой
Таким образом, вы генерируете перестановки. Все они.
Вкратце - perm генерирует все пространство возможных решений, начиная с пустого решения и проверяя, насколько данное решение возможно из действительного удаления.
?- perm( [ 1, 2, 3 ] , P )
P = [1, 2, 3];
P = [1, 3, 2];
P = [2, 1, 3];
P = [2, 3, 1];
P = [3, 1, 2];
P = [3, 2, 1];
no
Основная проблема - перестановочная функция. Когда он вызывается неявно, он всегда возвращает только одно значение.
Пролог - это язык, который всегда пытается доказать истинность утверждения, выводя его, используя приведенные аксиомы (факты или правила).
perm
не является функцией в смысле процедурного программирования. perm
это предикат, о котором мы говорим прологу две вещи:
- Пустой список - это перестановка.
List
это перестановка[H|Perm]
если есть списокRest
такой, чтоRest
получается путем удаленияH
отList
, а такжеRest
это перестановкаPerm
,
Когда спрошено, является ли некоторый список перестановкой другого, пролог попытается применить эти шаги деривации (рекурсивно), чтобы доказать это. Если эта рекурсия заходит в тупик, т. Е. Утверждение, которое не может быть доказано, так как никакие правила не могут быть применены к нему, оно возвращается.
Использование точки с запятой (;) в конце каждой перестановки дает вам пролог, пока нет другой перестановки, пролог должен сказать "Нет"