Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 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 умеет работать с потоками данных. Пото- ком называется последо- вательность фрагментов данных, которые посту- пают на вход программы и выводятся в результате её работы. Например, когда вы вводите в про- грамму символы, печатая их на клавиатуре, после- довательность этих сим- волов может рассматри- ваться как поток.
Перенаправление ввода Многие интерактивные программы получают пользовательский ввод с клавиатуры. Однако зачастую гораздо удобнее «скормить» программе содержимое текстового файла. Такой способ подачи входных данных называется перенаправлением ввода. Посмотрим, как перенаправление ввода работает с програм- мой на языке 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; просмотров: 204; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.145.199.240 (0.009 с.) |