.
Посмотрим, как перенаправление ввода работает с программой на языке Haskell. Для начала создадим текстовый файл, содержащий небольшое хайку, и сохраним его под именем haiku.txt:
>Я маленький чайник
>Ох уж этот обед в самолёте
>Он столь мал и невкусен
Ну да, хайку, прямо скажем, не шедевр – и что? Если кто в курсе, где найти хороший учебник по хайку, дайте знать.
Теперь напишем маленькую программу, которая непрерывно читает строку ввода и выводит её в верхнем регистре:
>import Control.Monad
>import Data.Char
>main = forever $ do
> l <- getLine
> putStrLn $ map toUpper l
Сохраните эту программу в файле capslocker.hs и скомпилируйте её.
Вместо того чтобы вводить строки с клавиатуры, мы перенаправим на вход программы содержимое файла haiku.txt. Чтобы сделать это, нужно добавить символ ><
после имени программы и затем указать имя файла, в котором хранятся исходные данные. Посмотрите:
>$ ghc capslocker
>[1 of 1] Compiling Main ( capslocker.hs, capslocker.o )
>Linking capslocker ...
>$ ./capslocker < haiku.txt
>Я МАЛЕНЬКИЙ ЧАЙНИК
>ОХ УЖ ЭТОТ ОБЕД В САМОЛЁТЕ
>ОН СТОЛЬ МАЛ И НЕВКУСЕН
>capslocker: : hGetLine: end of file
То, что мы проделали, практически эквивалентно запуску программы >capslocker
, вводу нашего хайку с клавиатуры и передаче символа конца файла (обычно это делается нажатием клавиш Ctrl+D). С тем же успехом можно было бы запустить >capslocker
и сказать: «Погоди, не читай ничего с клавиатуры, возьми содержимое этого файла!».
Получение строк из входного потока
Давайте посмотрим на действие ввода-вывода >getContents
, упрощающее обработку входного потока за счёт того, что оно позволяет рассматривать весь поток как обычную строку. Действие >getContents
читает всё содержимое стандартного потока ввода вплоть до обнаружения символа конца файла. Его тип: >getContents :: IO String
. Самое приятное в этом действии то, что ввод-вывод в его исполнении является ленивым. Это означает, что выполнение >foo <- getContents
не приводит к загрузке в память всего содержимого потока и связыванию его с именем >foo
. Нет, действие >getContents
для этого слишком лениво. Оно скажет: «Да, да, я прочту входные данные с терминала как-нибудь потом, когда это действительно понадобится!».
В примере capslocker.hs для чтения ввода строка за строкой и печати их в верхнем регистре использовалась функция >forever
. Если мы перейдём на >getContents
, то она возьмёт на себя все заботы о деталях ввода-вывода – о том, когда и какую часть входных данных нужно прочитать. Поскольку наша программа просто берёт входные данные, преобразует их и выводит результат, пользуясь