5.2.2. Ввод литер
Для ввода литер, набираемых на клавиатуре терминала, могут быть использованы предикаты get0(X) и get(X). Эти предикаты всегда согласуются с базой данных, если их аргументы неконкре-тизированы, а попытка повторного согласования всегда неудачна. При обработке целей, включающих эти предикаты, ЭВМ ожидает до тех пор, пока пользователь не наберет на клавиатуре какую-либо литеру. Указанные предикаты немного различаются тем, что get0(X) присвоит X любую набранную на клавиатуре литеру независимо от ее вида. Напротив, get(X) пропустит все
Если X уже присвоено значение, то целевое утверждение get(X) пропустит все управляющие литеры и сравнит следующую за ними печатаемую литеру со значением X. Доказательство согласованности целевого утверждения зависит от результата этого сравнения. Целевое утверждение get0(X) сравнивает X со следующей литерой и в зависимости от совпадения считается согласованным с базой данных или нет.
В следующем разделе приводятся некоторые примеры с использованием предикатов для чтения литер. Заранее обращаем внимание читателя на те случаи, когда возникает необходимость в возврате за целевое утверждение get.
5.3. Ввод предложений
В этом разделе мы представим программу, которая вводит предложение с терминала и преобразует его в список атомов языка Пролог. В программе определяется предикат ввести, имеющий один аргумент. Программа должна уметь определять, где заканчивается одно вводимое слово и начинается следующее. Поэтому предположим, что слово состоит из нескольких букв, цифр или специальных литер. Буквы и цифры уже были представлены в разд. 2.1. Мы будем рассматривать одиночную кавычку ''' и дефис '-' как специальные литеры. Литеры
, ; : ? ! .
будут рассматриваться как отдельные слова. Все другие литеры являются разделителями между словами. Предложение считается законченным, когда встречается одно из слов '.', '!' или '?'. Прописные буквы автоматически преобразуются в строчные, так что одно и то же слово всегда превращается в один и тот же атом. В результате такого определения программа будет поддерживать диалог с пользователем, подобный следующему:
?- ввести(S).
The man, who is very rich, saw John's watch.
S = [the,man,',',who,is,very,rich,',',saw,'John's',watch,'.']
В действительности мы вставили в представление предложения дополнительные одинарные кавычки, чтобы выделить некоторые атомы.
Программа использует предикат get0 для ввода литер с терминала. Затруднение, связанное с предикатом get0, состоит в том, что если литера прочитана с терминала этим предикатом, то она «ушла навсегда» и никакое другое целевое утверждение get0 или попытка вновь доказать целевое утверждение get0 не позволит получить доступ к этой литере вновь. Поэтому следует избегать возврата за точку использования get0, если мы хотим избежать «потери» литеры, которую он читает. Например, следующая программа, которая должна вводить литеры и печатать их снова, заменяя литеры а на b (код литеры 97 на код 98), не будет работать:
выполнить:- заменить_литеру, выполнить.
заменить_литеру:- get0(X) = 97,!, put(98).
заменить_литеру:- get0(X), put(X).
Приведенную программу в любом случае нельзя считать хорошей, потому что она будет работать вечно. Однако рассмотрим эффект попытки доказать согласованность целевого утверждения заме-нить_литеру. Если первое правило определения предиката заме-нить_литеру используется для чтения литеры, код которой отличен от 97, то возврат приведет к тому, что будет сделана попытка воспользоваться вместо него вторым правилом. Однако согласование целевого утверждения get0(X) во втором правиле приведет к тому, что X будет конкретизирована