- •Оглавление
- •Логическое программирование. Язык Prolog.
- •1. Предикаты Пример 1.1. Максимум из двух чисел
- •Пример 5.2. Вычисление факториала
- •6. Хвостовая рекурсия Пример 6.1. Вычиление факториала с с использованием хвостовой рекурсии
- •Пример 6.2. Вычисление чисел Фибоначчи
- •7. Обработка списков Пример 7.1. Вычисление длины списка
- •Пример 7.2. Проверка принадлежности элемента списку
- •Пример 7.3. Соединение двух списков
- •Пример 7.4. Обращение списка
- •Пример 7.5. Среднее арифметическое элементов списка.
- •8. Сортировка списков Пример 8.1. Пузырьковая сортировка
- •Пример 8.2. Сортировка вставкой
- •Пример 8.3. Сортировка выбором
- •9. Строки
- •Пример 9.3. Преобразование строки в список символов
- •Пример 9.4. Подсчет кол-ва вхождений заданного символа в строку
- •Пример 9.6. Замена заданного символа в строке – на другой
- •Пример 9.7. Удаление части строки
- •Пример 9.8. Копирование части строки
- •Пример 9.9. Вставка одной строки внутрь другой
- •10. Множества Пример 10.1. Превращение произвольного списка в множество
- •Пример 10.2. Операция объединения двух множеств.
- •Пример 10.3. Пересечение множеств
- •Пример 10.4. Разность множеств
- •Пример 10.5. Проверка, является ли одно множество подмножеством другого.
- •Пример 10.6. Предикат, реализующий отношение равенства двух множеств.
- •Пример 10.7. Определение собственного подмножества множества
- •Пример 10.8. Симметричная разность
- •Пример 10.9. Дополнение множества
- •11. Деревья Пример 11.1. Принадлежность элемента дереву
- •Пример 11.2. Замена заданного значения на другое в дереве
- •Пример 11.3. Подсчет общего количества вершин дерева
- •Пример 11.4. Подсчет количества листьев (узлов без сыновей)
- •Пример 11.5. Подсчет суммы чисел в вершинах дерева
- •Пример 11.6. Предикат, вычисляющий высоту дерева
- •Пример 11.7. Проверка принадлежности значения двоичному справочнику .
- •Пример 11.8. Добавление элемента в двоичный справочник
- •Пример 11.9. Генератор случайного двоичного справочника из чисел
- •Пример 11.10. Удаление заданного значения из двоичного справочника
- •Пример 11.11. Преобразование произвольного списка в двоичный справочник
- •Пример 11.12. Предикат, сворачивающий заданный двоичный справочник в список
- •12. Базы знаний Пример 12.1. Вычисление чисел Фибоначчи с запоминанием результатов
- •13. Логические задачи (головоломки) Пример 13.1. Перестановка кубиков
- •Пример 13.2. Ханойский башни
- •Пример 13.3. Волк, коза и капуста
- •Пример 13.4. Побег из Зурга
Пример 5.2. Вычисление факториала
Создадим предикат, который будет вычислять по натуральному числу его факториал.
Первый вариант. Можно проверить, что число, для которого применяется правило, больше единицы. Для единицы останется факт, утверждающий, что факториалом единицы будет единица. Выглядеть этот вариант будет следующим образом:
fact(1,1). /* факториал единицы равен единице */
fact(N,F):-
N>1, /* убедимся, что число больше единицы */
N1 is N-1,
fact(N1,F1), /* F1 = факториалу числа, на единицу меньшего исходного числа */
F is F1*N. /* факториал исходного числа = произведению F1 на само число */
Второй вариант решения проблемы - добавить в первое предложение процедуры отсечение. Напомним, что вызов отсечения приводит к тому, что предложения процедуры, расположенные ниже той, из которой оно было вызвано, не рассматриваются. И, соответственно, после того, как какая-то цель будет согласована с заголовком первого предложения, сработает отсечение, и попытка унифицировать цель с заголовком второго предложения не будет предпринята. Процедура в этом случае будет выглядеть так:
fact(1,1):-!. /* условие останова рекурсии */
fact(N,F):-
N1 is N-1,
fact(N1,F1), /* F1 = факториалу числа, на единицу меньшего исходного числа */
F is F1*N./* факториал исходного числа равен произведению F1 на само число */
6. Хвостовая рекурсия Пример 6.1. Вычиление факториала с с использованием хвостовой рекурсии
Надо добавить два дополнительных параметра, которые будут использоваться нами для хранения промежуточных результатов. Третий параметр нужен для хранения текущего натурального числа, для которого вычисляется факториал, четвертый параметр - для факториала числа, хранящегося в третьем параметре.
Запускать вычисление факториала мы будем при первом параметре равном числу, для которого нужно вычислить факториал. Третий и четвертый аргументы будут равны единице. Во второй аргумент по завершении рекурсивных вычислений должен быть помещен факториал числа, находящегося в первом параметре. На каждом шаге будем увеличивать третий аргумент на единицу, а второй аргумент умножать на новое значение третьего аргумента. Рекурсию нужно будет остановить, когда третий аргумент сравняется с первым, при этом в четвертом аргументе будет накоплен искомый факториал, который можно поместить в качестве ответа во второй аргумент.
Вся процедура будет выглядеть следующим образом:
fact2(N,F,N,F):-!. /* останавливаемся, когда третий аргумент равен первому*/
fact2(N,F,N1,F1):-
N2 is N1+1, /* N2 - следующее натуральное число после числа N1 */
F2 is F1*N2, /* F2 - факториал N2 */
fact2(N,F,N2,F2).
/* рекурсивный вызов с новым натуральным числом N2 и соответствующим ему
посчитанным факториалом F2 */
Остановить рекурсию можно, воспользовавшись отсечением в базисе рекурсии, как это было сделано выше, или добавив в начало второго предложения сравнение N1 с N.
Пример 6.2. Вычисление чисел Фибоначчи
Еще одна классическая задача, имеющая рекурсивное решение, связна с вычислением так называемых чисел Фибоначчи. Числа Фибоначчи можно определить так: первое и второе числа равны единице, а каждое последующее число является суммой двух предыдущих. Соответственно, третье число Фибоначчи будет равно двум, четвертое равно трем (сумма второго числа (один) и третьего числа (два)), пятое - пяти (сумма третьего и четвертого чисел, то есть двух и трех), шестое - восьми (сумма четвертого и пятого, трех и пяти) и т.д.
Базисов рекурсии в данном случае два. Первый будет утверждать, что первое число Фибоначчи равно единице. Второй базис - аналогичное утверждение про второе число Фибоначчи. Шаг рекурсии также будет необычным, поскольку будет опираться при вычислении следующего числа Фибоначчи не только на предшествующее ему число, но и на предшествующее предыдущему числу. В нем будет сформулировано, что для вычисления числа Фибоначчи с номером N сначала нужно вычислить и сложить числа с номерами N-1 и N-2.
Записать эти рассуждения можно так:
fib(1,1):- !. /* первое число Фибоначчи равно единице */
fib(2,1):- !. /* второе число Фибоначчи равно единице */
fib(N,F) :-
N1 is N-1, fib(N1,F1), /* F1 это N-1-е число Фибоначчи */
N2 is N-2, fib(N2,F2), /* F2 это N-2-е число Фибоначчи */
F is F1+F2. /* N-е число Фибоначчи равно сумме N-1-го и N-2-го чисел */
