В примере capslocker.hs для чтения ввода строка за строкой и печати их в верхнем регистре использовалась функция forever. Если мы перейдём на getContents, то она возьмёт на себя все заботы о деталях ввода-вывода – о том, когда и какую часть входных данных нужно прочитать. Поскольку наша программа просто берёт входные данные, преобразует их и выводит результат, пользуясь getContents, её можно написать короче:

import Data.Char

main = do

   contents <- getContents

   putStr $ map toUpper contents

Мы выполняем действие getContents и даём имя contents строке, которую она прочтёт. Затем проходим функцией toUpper по всем символам этой строки и выводим результат на терминал. Имейте в виду: поскольку строки являются списками, а списки ленивы, как и действие getContents, программа не будет пытаться прочесть и сохранить в памяти всё содержимое входного потока. Вместо этого она будет читать данные порциями, переводить каждую порцию в верхний регистр и печатать результат.

Давайте проверим:

$ ./capslocker < haiku.txt

Я МАЛЕНЬКИЙ ЧАЙНИК

ОХ УЖ ЭТОТ ОБЕД В САМОЛЁТЕ

ОН СТОЛЬ МАЛ И НЕВКУСЕН

Работает. А что если мы просто запустим capslocker и будем печатать строки вручную (для выхода из программы нужно нажать Ctrl+D)?

$ ./capslocker

хей хо

ХЕЙ ХО

идём

ИДЁМ

Чудесно! Как видите, программа печатает строки в верхнем регистре по мере ввода строк. Когда результат действия getContents связывается с идентификатором сontents, он представляется в памяти не в виде настоящей строки, но в виде обещания, что рано или поздно он вернёт строку. Также есть обещание применить функцию toUpper ко всем символам строки сontents. Когда выполняется функция putStr, она говорит предыдущему обещанию: «Эй, мне нужна строка в верхнем регистре!». Поскольку никакой строки ещё нет, она говорит идентификатору сontents: «Аллё, а не считать ли строку с терминала?». Вот тогда функция getContents в самом деле считывает с терминала и передаёт строку коду, который её запрашивал, чтобы сделать что-нибудь осязаемое. Затем этот код применяет функцию toUpper к символам строки и отдаёт результат в функцию putStr, которая его печатает. После чего функция putStr говорит, «Ау, мне нужна следующая строка, шевелись!» – и так продолжается до тех пор, пока не закончатся строки на входе, что мы обозначаем символом конца файла.

Теперь давайте напишем программу, которая будет принимать некоторый вход и печатать только те строки, длина которых меньше 15 символов. Смотрим:

main = do

   contents <- getContents

   putStr $ shortLinesOnly contents

shortLinesOnly :: String -> String

shortLinesOnly = unlines . filter (\line -> length line < 15) . lines

Фрагмент программы, ответственный за ввод-вывод, сделан настолько малым, насколько это вообще возможно. Так как предполагается, что наша программа печатает результат, основываясь на входных данных, её можно реализовать согласно следующей логике: читаем содержимое входного потока, запускаем на этом содержимом некоторую функцию, печатаем результат работы этой функции.

Функция shortLinesOnly принимает строку – например, такую: "коротко\nдлииииииииииинно\nкоротко". В этом примере в строке на самом деле три строки входных данных: две короткие и одна (посередине) длинная. В результате применения функции lines получаем список ["коротко", "длииииииииииинно", "коротко"]. Затем список строк фильтруется, и остаются только строки, длина которых меньше 15 символов: ["коротко", "коротко"]. Наконец, функция unlines соединяет элементы списка в одну строку, разделяя их символом перевода строки: "коротко\nкоротко".

Попробуем проверить, что получилось. Сохраните этот текст в файле shortlines.txt:

Я короткая

И я

А я длиииииииинная!!!

А уж я-то какая длиннющая!!!!!!!

Коротенькая

Длиииииииииииииииииииииинная

Короткая

Сохраните программу в файле shortlinesonly.hs и скомпилируйте её:

$ ghc shortlinesonly.hs

[1 of 1] Compiling Main  ( shortlinesonly.hs, shortlinesonly.o )

Linking shortlinesonly ...

Чтобы её протестировать, перенаправим содержимое файла shortlines.txt на её поток ввода:

$ ./shortlinesonly < shortlines.txt

Я короткая

И я

Коротенькая

Короткая

Перейти на страницу:

Похожие книги