5.4.2. Чтение файлов
Предикаты, которые предоставляет Пролог для переключения текущего входного потока данных, аналогичны предикатам, обсуждавшимся выше. Целевое утверждение see(X) переключает текущий входной поток данных на файл с указанным именем. Так же как и tell, это целевое утверждение не может быть доказано вновь, и выполненное предикатом изменение входного потока не переделывается при возврате. При первом выполнении see(X) для некоторого файла X этот файл становится открытым (для чтения), при этом чтение начинается с начала файла. Последующая операция чтения продолжает читать данные с того места, где закончила предыдущая операция. И так до тех пор, пока не будет сделано явного закрытия файла. С этого момента новая попытка читать из файла приведет к тому, что файл будет открыт и чтение начнется с начала файла, как и прежде. Текущий входной поток данных может быть определен в результате выполнения seeing(X), и текущий входной поток данных может быть переключен обратно на ввод с терминала в результате выполнения целевого утверждения seen, которое также закрывает файл.
5.4.3. Ввод программ
Чтение данных из файлов и запись данных в файлы наиболее полезны тогда, когда объем данных, с которыми работает наша программа и которые мы хотим поместить в базу данных, превосходит тот объем, который мы можем вводить вручную при каждом сеансе работы с ЭВМ. В Прологе файлы используются главным образом для хранения программ. Если текст Пролог-программы содержится в некотором файле, то мы можем прочитать все утверждения, содержащиеся в файле, и поместить их в базу данных, воспользовавшись для этого предикатом consult. Если значением X является имя файла, то цель consult(X) прочитает утверждения (факты и правила) и целевые утверждения из этого файла. Большинство реализаций Пролога имеют специальную форму записи для предиката consult, позволяющую прочитать последовательно один за другим список файлов. Если вопрос к Пролог-системе имеет вид списка атомов, то Пролог-система прочитает каждый файл из этого списка. В качестве примера использования такой формы записи приведем следующий вопрос:
?- файл1, отображение, эксперт.
Этот вопрос обрабатывается таким образом, как если бы Пролог выполнял целевое утверждение consultall(X), где X - это список, заданный в вопросе, а предикат consultall определен следующим образом:
consultall([]).
consultall(H|T]):- consult(H), consultall(T).
Однако короткая списковая запись более экономична, а это особенно важно, если принять во внимание, что самое первое действие, которое выполняет работающий с Прологом программист,- это чтение из файлов своих предикатов. Предикат consult автоматически прекращает чтение утверждений, когда встречается конец файла. В разд. 6.1 предикат consult описывается более подробно.
5.5. Объявление операторов
Причина, по которой операторы рассматриваются в главе, посвященной вводу-выводу, состоит в том, что операторы предоставляют некоторые синтаксические удобства при чтении и записи термов. Никаких других причин для введения операторов нет. Для начала коротко напомним сказанное в разд. 2.3, а затем расскажем о том, как объявляются операторы.
Синтаксис языка разрешает использование операторов, обладающих следующими тремя свойствами: позицией, приоритетом и ассоциативностью. По занимаемой позиции операторы могут быть инфиксными, постфиксными или префиксными (оператор, имеющий два аргумента, может располагаться между аргументами; оператор с одним аргументом может находиться либо после аргумента, либо перед ним). Приоритет оператора – это некоторое целое число, диапазон изменения которого зависит от конкретной реализации Пролога. Предположим, что оно находится в диапазоне от 1 до 255. Приоритет используется для того, чтобы придать однозначную интерпретацию выражениям в тех случаях, когда синтаксис термов не задан явно с помощью скобок. Ассоциативность необходима для придания однозначной интерпретации выражениям, в которых имеются два оператора с одинаковыми приоритетами. Оператору в языке Пролог соответствует специальный атом, который специфицирует позицию и ассоциативность оператора. Для инфиксных операторов возможны следующие спецификации:
xfx xfy yfx yfy
Чтобы понять смысл этих спецификаций, их полезно рассматривать как «образцы» возможного использования операторов. В приведенных образцах буква f представляет оператор, а х и у – аргументы. Таким образом, во всех приведенных выше образцах оператор должен находиться между двумя аргументами, т. е. он является инфиксным оператором. В соответствии с этим соглашением
fx fy
есть две спецификации для префиксных операторов (оператор записывается перед его единственным аргументом). Точно так же
xf yf
представляют возможные спецификации для постфиксных операторов. Может вызвать недоумение использование двух букв для обозначения аргументов. Использование букв х и у в той или иной позиции позволяет выразить информацию об ассоциативности оператора. В предположении, что выражение не содержит скобок, буква у указывает, что соответствующий ей аргумент может содержать операторы с приоритетом, равным приоритету данного оператора или с более низким приоритетом. Напротив, буква х указывает, что каждый оператор в соответствующем ей аргументе должен иметь строго более низкий приоритет по сравнению с приоритетом данного оператора. Рассмотрим, что это значит для оператора +, объявленного как yfx. Если имеется выражение
а + b + с
то для него возможны две следующие интерпретации:
(а + b) + с а + (b + с)
Вторая интерпретация исключается, так как при этом аргумент, стоящий после первого вхождения +, содержит оператор с тем же самым приоритетом (второй оператор +). Это противоречит тому, что в спецификации оператора + после f стоит х.
Оператор, имеющий спецификацию yfx, является левоассоциативным. Аналогично оператор со спецификацией xfy является правоассоциативным. Если мы знаем необходимую ассоциативность объявляемого инфиксного оператора, то это значит, что однозначно определяется соответствующая оператору спецификация.
Заметим, что использование букв х и у в двух других случаях имеет тот же смысл относительно того, какие операторы могут появляться в соответствующей позиции при отсутствии скобок. Это значит, что, например, последовательность
not not a
допустима синтаксически, если оператор not объявлен как fy, и недопустима в случае, когда он объявлен как fx.
Если мы хотим объявить на Прологе оператор с заданными позицией, приоритетом и ассоциативностью таким образом, чтобы Пролог распознавал его при вводе и выводе термов, то мы используем встроенный предикат ор. Если Имя - это оператор, который мы желаем иметь (атом, который мы хотим сделать оператором), Приоритет - приоритет оператора (целое число в соответствующем диапазоне) и Спецификация - спецификация, определяющая положение и ассоциативность оператора (один из приведенных выше атомов), то такой оператор может быть объявлен с помощью выполнения следующего целевого утверждения
?- ор (Приоритет,Спецификация,Имя).
Если объявление оператора является допустимым, то эта цель будет достигнута.
В качестве примера объявления операторов далее приводится полный список базовых операторов, обсуждаемых в данной книге. Конкретные реализации Пролога могут иметь несколько отличный набор «стандартных» операторов; может потребоваться масштабирование указанных приоритетов. Однако взаимный порядок операторов в иерархии приоритетов обычно остается неизменным.