Пример 3.6. Печатаются «в столбик» квадраты чисел натурального ряда, пока очередной квадрат не превысит число 1000:
печать_квадратов :– N = 1, квадрат(N, R), write(R), nl,
условие(R), !.
квадрат(N, R) :– R is N^2.
квадрат(N, R) :– N1 is N+1, квадрат(N1, R).
условие(R) :– R > 1000.
UDR-метод (метод «user defined repeat»)
Есть некоторое безвозвратное действие(X), вырабатывающее значение выходного параметра X. Это действие должно многократно повторяться, пока значение параметра X не станет удовлетворять некоторому условию. Для того, чтобы действие стало возвратным, используется встроенный предикат repeat/0. Его семан-
тику поясняет следующее «определение»: repeat.
repeat :– repeat.
Подцель repeat записывается перед подцелью действие(X) в правой части правила, реализующего цикл.
Пример 3.7. Печатаются «в столбик» вводимые пользователем слова, пока не будет введено слово finish:
печать_слов :– repeat, read(W), write(W), nl, условие(W). условие(W) :– W == finish.
Подцель repeat при первом вызове срабатывает без всяких условий. После невыполнения условия осуществляется возврат к этой подцели. Согласно 2-му правилу создаётся новая подцель repeat, которая опять срабатывает без каких-либо условий. И т.д.
4. Встроенный предикат определения новой операции
На предыдущей лекции было отмечено, что кроме структур, для записи которых используются скобки, например f(a, b, c), в языке Пролог используются так называемые бесскобочные структуры инфиксного типа, например a f b. Это бинарные (двухаргументные) бесскобочные структуры. К этому же типу можно условно отнести унарные (одноаргументные) бесскобочные структуры: a f и f a.
51
Использование таких структур облегчает чтение многих запи-
сей, например вместо знает(Джон, Мери) и человек(Сократ) бо-
лее естественны и понятны записи: Джон знает Мери и Сократ человек.
Для инфиксной структуры в языке Пролог есть специальное название: операция. Функтор такой структуры называется оператором, аргументы структуры – операндами.
Когда выражение языка содержит несколько операций, необходимо знать, в каком порядке они применяются.
Пусть, например, @ и # – операторы каких-то бинарных операций над числами. Как понимать следующую запись:
2 # 3 @ 4 @ 5 # 6?
Во-первых, надо знать, какая операция из двух имеет более высокий приоритет, а во-вторых, – правоили левоассоциативной является каждая из них. Естественно, что «узнать» это Прологсистема должна до начала логического вывода, поэтому в начале базы данных часто записываются директивы вида
:- op(700, xfy, #). :- op(600, yfx, @).
В директивах применяется встроенный предикат Пролога op/3, все аргументы которого – входные параметры. 1-й аргумент – значение приоритета определяемой операции, 2-й аргумент – спецификация ассоциативности, 3-й аргумент – знак оператора.
Значение приоритета операции важно только по отношению к значениям приоритета других операций: меньше (выше) или больше (ниже).
Значения второго аргумента означают следующее: yfx – левоассоциативная операция,
xfy – правоассоциативная операция, xfx – неассоциативная операция,
yf и fy – допускающие вложенность
(например: not not true),
xf и fx – не допускающие вложенности
(например: Джон человек человек).
Таким образом, в выражении 2 # 3 @ 4 @ 5 # 6 операции применяются в следующем порядке: ( 2 # ((( 3 @ 4 ) @ 5 ) # 6)).
52
На следующей лекции будут рассмотрены ещё несколько типов встроенных предикатов, а также популярные в Прологе рекурсивные методы программирования. Для более детального знакомства с этими вопросами автор рекомендует книги Дж. Стобо [5] и Дж. Малпаса [6].
53
Лекция 4
Основы программирования на Прологе (продолжение)
В данной лекции, в дополнение к тому, что рассматривалось в предыдущей лекции, представлены ещё две категории встроенных предикатов: 1) для преобразования структур данных и 2) для про-
верки типа терма. Кроме встроенных предикатов, обсуждаются примеры определений пользовательских предикатов, которые, в значительной степени, носят универсальный характер или могут понадобиться при решении задач самых разных классов. Особое внимание при этом уделяется способам и предикатам обработки списков. Анализируются особенности рекурсивных методов решения задач, характерных для Пролога – метод входящей рекурсии и
метод исходящей рекурсии.
1. Встроенные предикаты преобразования структур
Рассмотрим только четыре из множества таких предикатов.
Предикат name/2.
Данный предикат преобразует атомоподобный терм (атом, число или строку) в список кодов символов, из которых этот терм состоит. Или наоборот, список кодов – в атомоподобный терм. Например:
?– name(ася, X). → |
X = [1072, 1089, 1103] |
?– name(X, [97, 98, 98, |
97]). → X = abba |
Предикат functor/3.
Данный предикат анализирует структуру произвольного вида (1-й аргумент): определяет её имя (2-й аргумент) и её арность (3-й аргумент). Или наоборот – синтезирует структуру произвольного вида (1-й аргумент) по известному имени (2-й аргумент) и арности (3-й аргумент). Например:
?– functor(f(a, b, c), X, Y). |
→ |
X = f, Y = 3 |
?– functor(X, f, 3). → |
X = f(_, _, _) |
|
54
Предикат arg/3.
В отличие от предыдущих предикатов этот предикат работает только «в одну сторону»: его спецификация arg/(i, i, o). Для заданной структуры произвольного вида (2-й аргумент) по номеру ее компонента (1-й аргумент) находится значение этого компонента (3-й аргумент). Например:
?– arg(2, f(a, b, c), X). ?– arg(2, [a, b, c, d], X).
→X = b
→X = [b, c, d]
«В обратную сторону» предикат arg/3 работать не может – по значению компонента структуры нельзя находить его номер.
Предикат =../2.
Данный предикат преобразует структуру произвольного вида (1- й аргумент) в список (2-й аргумент). Или наоборот – список в структуру. Голова списка (1-й элемент) – имя структуры, хвост списка (2-й элемент) – компоненты структуры. Таким образом, длина списка на единицу больше числа компонентов структуры. Примеры:
?– f(a, b, c) =.. X. ?– X =.. [f, a, b, c].
→X = [f, a, b, c]
→X = f(a, b, c)
2. Примеры предикатов обработки списков
Список, как уже было отмечено, является наиболее используемой структурой данных Пролога. Поэтому в разных реализациях Пролога (в разных Пролог-системах) почти всегда присутствуют встроенные предикаты обработки списков: member/2, append/3, reverse/2, sort/2 и т.д. Но иногда их приходится определять. Приведем определения этих предикатов без комментариев. (Автор оставляет слушателям или читателям возможность самостоятельно изучить их семантику непосредственно по определениям.)
55