Изучай Haskell во имя добра! (Липовача) - страница 128

, её можно написать короче:

>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

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