![]() Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву ![]() Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Некоторые полезные функции для ввода-вывода
В стандартной библиотеке языка Haskell имеется масса полезных функций и действий ввода-вывода. Давайте рассмотрим некоторые из них и увидим, как ими пользоваться.
Функция putStr Функция putStr похожа на функцию putStrLn – она принимает стро- ку как параметр и возвращает действие ввода-вывода, которое печа- тает строку на терминале. Единственное отличие: функция putStr не выполняет перевод на новую строку после печати, как это делает putStrLn.
main = do
putStr "Привет, " putStr "я " putStrLn "Энди!" Если мы скомпилируем эту программу, то при запуске получим:
Привет, я Энди!
Функция putChar
Функция putChar принимает символ и возвращает действие ввода- вывода, которое напечатает его на терминале. main = do
putChar 'А' putChar 'Б' putChar 'В' Функция putStr определена рекурсивно с помощью функции putChar. Базовый случай для функции putStr – это пустая строка. Если печатаемая строка пуста, функция возвращает пустое дейс- твие ввода-вывода, то есть return (). Если строка не пуста, функция выводит на терминал первый символ этой строки, вызывая функ- цию putChar, а затем выводит остальные символы, снова рекурсив- но вызывая саму себя. putStr:: String –> IO () putStr [] = return () putStr (x:xs) = do
putChar x putStr xs Как вы заметили, мы можем использовать рекурсию в системе ввода-вывода подобно тому, как делаем это в чистом коде. Точно так же образом мы определяем базовые случаи, а затем думаем, что будет результатом. В результате мы получим действие, которое вы- ведет первый символ, а затем остаток строки.
Функция print Функция print принимает значение любого типа – экземпляра класса Show (то есть мы знаем, как представить значение этого типа
в виде строки), вызывает функцию show, чтобы получить из дан- ного значения строку, и затем выводит её на экран. По сути, это putStrLn.show. Это выражение сначала вызывает функцию show на переданном параметре, а затем «скармливает» результат функции putStrLn, которая возвращает действие ввода-вывода; оно, в свою очередь, печатает заданное значение. main = do print True print 2 print "ха-ха" print 3.2
print [3,4,3] После компиляции и запуска получаем: True 2 "ха-ха" 3.2
[3,4,3] Как вы могли заметить, это очень полезная функция. Помните, мы говорили о том, что действия ввода-вывода выполняются толь- ко из функции main или когда мы выполняем их в интерпретаторе GHCi? После того как мы напечатаем значение (например, 3 или [1, 2, 3]) и нажмём клавишу «Ввод», интерпретатор GHCi вызовет функцию print с введённым значением для вывода на терминал!
ghci> 3 ghci> print 3 ghci> map (++"!") ["хей","хо","ууу"] ["хей!","хо!","ууу!"] ghci> print $ map (++"!") ["хей","хо","ууу"]
["хей!","хо!","ууу!"] Как правило, мы хотим видеть строку на экране, не заключён- ную в кавычки, поэтому для печати строк обычно используется функция putStrLn. Но для печати значений других типов преиму- щественно используется функция print.
Функция when Функция when находится в модуле Control.Monad (чтобы к ней обра- титься, воспользуйтесь import Control.Monad). Она интересна, по- тому что выглядит как оператор управления ходом вычислений, но на самом деле это обычная функция. Она принимает булевское значение и действие ввода-вывода. Если булевское значение истин- но, она возвращает второй параметр – действие ввода-вывода. Если первый параметр ложен, функция возвращает return (), то есть пус- тое действие.
Напишем программу, которая запрашивает строку текста и, ес- ли строка равна «РЫБА-МЕЧ», печатает её: import Control.Monad
main = do input <- getLine
when (input == "РЫБА-МЕЧ") $ do putStrLn input Без when нам понадобилось бы написать нечто такое: main = do input <- getLine
if (input == "РЫБА-МЕЧ") then putStrLn input else return () Как вы видите, функция when позволяет выполнить заданное действие в случае, если некоторое условие истинно, и ничего не делать в противном случае.
Функция sequence
Функция sequence принимает список действий ввода-вывода и воз- вращает одно действие ввода-вывода, последовательно выполня- ющее действия из списка. Результат выполнения этого действия – список результатов вложенных действий. Сигнатура типа функции: sequence:: [IO a] –> IO [a]. Выполним следующее: main = do a <– getLine
b <– getLine c <– getLine print [a,b,c] То же самое, но с использованием функции sequence:
main = do
rs <– sequence [getLine, getLine, getLine] print rs Итак, выражение sequence [getLine, getLine, getLine] создаст действие ввода-вывода, которое выполнит функцию getLine три раза. Если мы свяжем это действие с именем, результат будет пред- ставлять собой список результатов действий из изначального спис- ка, в нашем случае – то, что пользователь введёт с клавиатуры.
Функцияsequenceобычноиспользуется, еслимыхотимпройтись по списку функциями print или putStrLn. Вызов map print [1,2,3,4] не создаёт действия ввода-вывода – вместо этого создаётся список действий. Такой код на самом деле эквивалентен следующему: [print 1, print 2, print 3, print 4]
Если мы хотим преобразовать список действий в действие, то необходимо воспользоваться функцией sequence: ghci> sequence $ map print [1,2,3,4] 1
4 [(),(),(),()] Но что это за [(),(),(),()] в конце вывода? При выполнении в GHCi действия ввода-вывода помимо самого действия выводит- ся результат выполнения, но только если этот результат не есть (). Поэтому при выполнении в GHCi putStrLn "ха-ха" просто выводит- ся строка – результатом является (). Если же попробовать ввести getLine, то помимо собственно ввода с клавиатуры будет выведено введённое значение – результатом является IO String.
Функция mapM Поскольку применение функции, возвращающей действие ввода- вывода, к элементам списка и последующее выполнение всех полу-
ченных действий очень распространено, для этих целей были вве- дены две вспомогательные функции – mapM и mapM_. Функция mapM принимает функцию и список, применяет функцию к элементам списка, сводит элементы в одно действие ввода-вывода и выпол- няет их. Функция mapM_ работает так же, но отбрасывает результат действия ввода-вывода. Она используется, когда нам не важен ре- зультат комбинированного действия ввода-вывода. ghci> mapM print [1,2,3] 1 3 [(),(),()] ghci> mapM_ print [1,2,3] 1
3
Функция forever
Функция forever принимает действие ввода-вывода – параметр и воз- вращает действие ввода-вывода – результат. Действие-результат будет повторять действие-параметр вечно. Эта функция входит в модуль Control.Monad. Следующая программа будет бесконечно спрашивать у пользователя строку и возвращать её в верхнем ре- гистре: import Control.Monad import Data.Char
main = forever $ do putStr "Введите что-нибудь: " l <– getLine
putStrLn $ map toUpper l
Функция forM Функция forM (определена в модуле Control.Monad) похожа на функ- цию mapM, но её параметры поменяны местами. Первый параметр – это список, второй – это функция, которую надо применить к спис- ку и затем свести действия из списка в одно действие. Для чего
это придумано? Если творчески использовать лямбда-выражения и ключевое слово do, можно проделывать такие фокусы: import Control.Monad
main = do colors <– forM [1,2,3,4] (\a –> do putStrLn $ "С каким цветом ассоциируется число " ++ show a ++ "?" color <– getLine return color)
putStrLn "Цвета, ассоциирующиеся с 1, 2, 3 и 4: " mapM putStrLn colors Вот что мы получим при запуске: С каким цветом ассоциируется число 1? белый С каким цветом ассоциируется число 2? синий С каким цветом ассоциируется число 3? красный С каким цветом ассоциируется число 4? оранжевый Цвета, ассоциирующиеся с 1, 2, 3 и 4: белый
синий красный оранжевый
Анонимная функция (\a –> do...) – это функция, которая при- нимает число и возвращает действие ввода-вывода. Нам пришлось поместить её в скобки, иначе анонимная функция решит, что сле- дующие два действия ввода-вывода принадлежат ей. Обратите вни- мание, что мы производим вызов return color внутри блока do. Это делается для того, чтобы действие ввода-вывода, возвращаемое бло- ком do, содержало в себе цвет. На самом деле мы не обязаны этого делать, потому что функция getLine уже содержит цвет внутри себя. Выполняя color <– getLine и затем return color, мы распаковываем ре- зультат getLine и затем запаковываем его обратно, то есть это то же самое, что просто вызвать функцию getLine. Функция forM (вызывае- мая с двумя параметрами) создаёт действие ввода-вывода, результат
которого мы связываем с идентификатором colors. Этот идентифи- катор – обычный список, содержащий строки. В конце мы распеча- тываем все цвета, вызывая выражение mapM putStrLn colors. Вы можете думать, что функция forM имеет следующий смысл: «Создай действие ввода-вывода для каждого элемента в списке. Ка- ков будет результат каждого такого действия, может зависеть от элемента, из которого оно создаётся. После создания списка дейс- твий исполни их и привяжи их результаты к чему-либо». Однако мы не обязаны их связывать – результаты можно просто отбросить. На самом деле мы могли бы сделать это без использования функ- ции forM, но так легче читается. Обычно эта функция используется, когда нам нужно отобразить (map) и объединить (sequence) действия, которые мы тут же определяем в секции do. Таким образом, мы могли бы заменить последнюю строку на выражение forM colors putStrLn.
Обзор системы ввода-вывода В этой главе мы изучили основы системы ввода-вывода языка Has- kell. Также мы узнали, что такое действия ввода-вывода, как они позволяют выполнять ввод-вывод, в какой момент они выполня- ются. Итак, повторим пройденное: действия ввода-вывода – это значения, такие же, как любые другие в языке Haskell. Мы можем передать их в функции как параметры, функции могут возвращать действия ввода-вывода в качестве результата. Они отличаются тем, что если они попадут в функцию main (или их введут в интерпре- таторе GHCi), то будут выполнены. В этот момент они могут вы- водить что-либо на экран или управлять звуковыводящим устройс- твом. Каждое действие ввода-вывода может содержать результат общения с реальным миром. Не думайте о функции, например о putStrLn, как о функции, ко- торая принимает строку и печатает её на экране. Думайте о ней как о функции, которая принимает строку и возвращает действие вво- да-вывода. Это действие при выполнении печатает нечто ценное на вашем терминале.
БОЛЬШЕ ВВОДА И ВЫВОДА Теперь, когда вы понимаете идеи, лежащие в основе ввода-вывода в языке Haskell, можно приступать к интересным штукам. В этой главе мы будем обрабатывать файлы, генерировать случайные чис- ла, читать аргументы командной строки и много чего ещё. Будьте готовы!
Файлы и потоки
вательность фрагментов данных, которые посту- пают на вход программы и выводятся в результате её работы. Например, когда вы вводите в про- грамму символы, печатая их на клавиатуре, после- довательность этих сим- волов может рассматри- ваться как поток.
Перенаправление ввода Многие интерактивные программы получают пользовательский ввод с клавиатуры. Однако зачастую гораздо удобнее «скормить» программе содержимое текстового файла. Такой способ подачи входных данных называется перенаправлением ввода.
Посмотрим, как перенаправление ввода работает с програм- мой на языке 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: <stdin>: hGetLine: end of file
То, что мы проделали, практически эквивалентно запуску про- граммы capslocker, вводу нашего хайку с клавиатуры и передаче сим- вола конца файла (обычно это делается нажатием клавиш Ctrl + D). С тем же успехом можно было бы запустить capslocker и сказать: «Погоди, не читай ничего с клавиатуры, возьми содержимое это- го файла!».
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Последнее изменение этой страницы: 2017-02-17; просмотров: 187; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.145.166.28 (0.057 с.) |