Ну, все, что я могу сказать, это то, что способ решения проблемы во многом зависит от самой проблемы. Существует ряд проблем, которые можно решить с помощью рекурсии , где Prolog хорошо подходит для их решения.
В задачах такого рода можно найти решение более крупной проблемы, разделив ее на два или более классов дел.
В одном классе у нас есть «базовые случаи», где мы предоставляем решение проблемы, когда входные данные не могут быть далее разделены на более мелкие случаи.
Другой класс - это «рекурсивные случаи», где мы разбиваем входные данные на части, решаем их отдельно, а затем «объединяем» результаты, чтобы найти решение для этого более крупного ввода.
В примере для flatten / 2 мы хотим взять в качестве входных данных список элементов, где каждый элемент также может быть списком, а результатом должен быть список, содержащий все элементы из входных данных. Поэтому мы разбиваем проблему на ее случаи.
Мы будем использовать вспомогательный аргумент для хранения промежуточного уплощенного списка, и именно поэтому мы реализуем flatten / 3.
Поэтому наш предикат flatten / 2 просто вызовет flatten / 3, используя пустой список в качестве начального промежуточного уплощенного списка:
flatten(List, Flattened):-
flatten(List, [], Flattened).
Теперь для предиката flatten / 3 у нас есть два базовых случая. Первый имеет дело с пустым списком. Обратите внимание, что мы не можем далее разделить проблему, когда входные данные являются пустым списком. В этом случае мы просто берем промежуточный плоский список в качестве нашего результата.
flatten([], Flattened, Flattened).
Теперь мы делаем рекурсивный шаг. Это включает взятие списка ввода и разделение проблемы в два шага. Первым шагом является выравнивание первого элемента этого списка ввода. Вторым шагом будет рекурсивное выравнивание остального:
flatten([Item|Tail], L, Flattened):-
flatten(Item, L1, Flattened),
flatten(Tail, L, L1).
Хорошо, поэтому вызов flatten (Item, L1, Flattered) выравнивает первый элемент, но передает в качестве промежуточного списка несвязанную переменную L1. Это всего лишь хитрость, так что при возврате предиката переменная L1 все еще остается неограниченной, а Flatlined будет иметь вид [... | L1], где ... - сплющенные элементы Item.
Следующий шаг, который вызывает flatten (Tail, L, L1) , выравнивает остальную часть списка ввода, и результат ограничен L1.
Наше последнее предложение на самом деле является другим базовым случаем, который касается отдельных предметов (которые не являются списками). Поэтому имеем:
flatten(Item, Flattened, [Item|Flattened]):-
\+ is_list(Item).
, который проверяет, является ли элемент списком, и когда он не является списком, он связывает результат как список с заголовком head = Item и как промежуточный плоский список.