Программирование на языке Пролог | страница 106



, он возьмет следующую литеру, но при этом опять не будет никакого выбора. Мы можем определить новый предикат new_get следующим образом:


new_get(X):- repeat, get0(X).


Предикат new_get обладает следующим свойством: он порождает одно за одним значения всех последующих литер (в порядке их поступления) как альтернативные решения. Почему так получается? Когда мы первый раз вызываем new_get(X), то подцель repeat согласуется и подцель getO(X) тоже, при этом переменная X конкретизируется очередной литерой. Когда мы инициируем возврат, то выясняется, что последним местом, где имелся выбор, является repeat. Пролог забывает все, что было сделано с того момента, а повторное согласование целевого утверждения repeat успешно завершается. Теперь он вновь должен обратить свое внимание на getO(X). К этому моменту текущей литерой является следующая литера, и в результате X получает в качестве значения вторую литеру.

Мы можем использовать наше определение new_get, чтобы определить другой полезный предикат. Предикат get обычно является встроенным. Когда Пролог обрабатывает целевое утверждение get(X), он рассматривает его как указание читать литеры до тех пор, пока он не найдет очередную неуправляющую литеру, имеющую изображение при печати (пробел, признак конца строки и т. д.). Затем он пытается сопоставить целочисленный код этой литеры со значением X. Мы можем написать приблизительное определение предиката get следующим образом:


get(X):- new_get(X), X › 32.


Чтобы понять это определение, нужно вспомнить, что в кодировке ASCII все неуправляющие (печатаемые) литеры имеют код, превышающий 32, все остальные литеры имеют код, меньший или равный 32. Что происходит при попытке согласовать get(X)? Прежде всего new_get(X) сопоставляет X с текущей литерой, введенной в систему. Если ее код меньше или равен 32, то следующее целевое утверждение неверно и new_get будет вынужден породить следующую литеру как следующее возможное решение. Эта литера будет затем сравнена с 32 и так далее. В конце концов new_get найдет неуправляющую литеру, сравнение закончится успешно и код этой литеры будет возвращен в качестве результата get.

Упражнение 6.1. Приведенное определение предиката get не будет работать надлежащим образом, если мы обратимся к целевому утверждению get(X) с уже определенным значением X. Почему это происходит?

Неприятность, связанная с предикатом repeat, состоит в том, что он всегда имеет альтернативное решение. Следовательно, в процессе возврата