printЛогическое программирование

printПредикаты для ввода и вывода данных

Предикаты ввода/вывода изменяют состояние входного или выходного потока независимо от их успешности, при возврате исходное состояние потока также не восстанавливается. Для всех предикатов ввода-вывода можно указать в качестве дополнительного первого аргумента используемый поток ввода или вывода; по умолчанию ввод и вывод осуществляется в текущий поток ввода и вывода (на экран).
Предикаты set_input/1 и set_output/1 позволяют перенаправить ввод или вывод на ранее открытые файлы. Узнать текущие потоки по умолчанию можно с помощью предикатов current_input/1 и current_output/1.
Для открытия файлов используется предикат open/4, для закрытия – close/1. Первый аргумент open – атом с именем файла, второй – режим открытия (read, write или append), третий – переменная, куда будет помещен идентификатор потока, четвертый – список опций, например, тип потока (type(binary) для бинарных потоков, по умолчанию используется type(text)) или глобальное имя для потока, которое можно использовать вместо идентификатора (см. пример).
Предикат get_code осуществляют посимвольный ввод из текущего входного потока данных. Цель get_code(X) успешна, если X является ASCII-кодом очередного символом текущего входного потока. Аналогичный предикат get_byte используется для бинарных файлов.
main:-open('c:/work/input.txt',read,X,[alias(input)]),
      read_content(L),close(X). /* или close(input) */
read_content(L):-get_code(input,S),
     (S= -1 /* EOF */ -> L=[];
      read_content(T),L=[S|T]).
Предикат read(X) читает очередной терм из текущего входного потока и сопоставляет его с X. Ввод терма должен заканчиваться точкой, которая не становится частью терма и удаляется из входного потока. При интерактивном вводе также следует нажать клавишу Enter. Для ввода чисел и атомов в GNU Prolog удобно использовать предикаты read_integer/1, read_number/1, read_atom/1.
Предикат put_code(X) записывает в текущий выходной поток данных символ, ASCII-код которого задан в X. Аналогичный предикат put_byte используется для бинарных файлов.
Предикат nl записывает в текущий выходной поток символы перехода на новую строку. Для форматирования можно использовать предикат tab(N), который записывает в текущий выходной поток N пробелов (нестандартный, но есть во многих реализациях Пролога).
Предикат write(X) записывает терм X в текущий выходной поток. Предикат writeq(X) записывает терм X, добавляя апострофы у некоторых атомов так, чтобы терм можно было потом считать. Предикат write_canonical(X) работает аналогично, но все объявления операторов игнорируются, что позволяет увидеть внутреннее представление структур.
?-write(1+'2*3').
1+2*3
?-writeq(1+'2*3').
1+'2*3'
?-write_canonical(1+2*3).
+(1,*(2,3))
Предикат flush_output принудительно выводит буфер, может быть полезным при интерактивном вводе.
ask(N):-repeat,write('Введите число от 1 до 10: '),flush_output,read_integer(N),N>=1,N=<10,!.


Упражнения
1. Определите предикат для печати всех потомков X, используя информацию из БД о родственных связях из главы 1. Каждый потомок выводится на отдельной строке с отступом, соответствующим его дальности родства с X.
?-потомки(адам).
адам
  каин
    сим
    ...
  авель
2. Определите предикаты для ввода строки текста до точки и для разбиения предложения на отдельные слова по пробелам.
?-ввод_строки(L),разбиение(L,R).
Это пример предложения.     % вводит пользователь
R=[Это,пример,предложения]
3. Определите предикат для печати арифметического выражения со скобками, указывающими порядок вычисления выражения.
?-печать(a+b*c/2-3).
((a+((b*c)/2))-3)
4. Определите предикат для печати сложного списка. Если список не содержит других списков, то выводить его целиком на одной строке, иначе каждый элемент списка выводить на отдельной строке.
?-печать_списка([a,[[d,e],f]]).
[
  a,
  [                   
    [d,e],            
    f
  ]
]
loading