Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Использование ключевого слова let внутри блока doСодержание книги
Поиск на нашем сайте
Помните связывания при помощи ключевого слова let? Если уже подзабыли, освежите свои знания. Связывания должны быть тако- го вида: let < определения > in < выражение >, где < определения > – это име- на, даваемые выражениям, а < выражение > использует имена из < опре- делений >. Также мы говорили, что в списковых выражениях часть in не нужна. Так вот, в блоках do можно использовать выражение let таким же образом, как и в списковых выражениях. Смотрите: import Data.Char
main = do putStrLn "Ваше имя?" firstName <– getLine putStrLn "Ваша фамилия?" lastName <– getLine let bigFirstName = map toUpper firstName bigLastName = map toUpper lastName putStrLn $ "Привет, " ++ bigFirstName ++ " " ++ bigLastName ++ ", как дела?" Видите, как выровнены операторы действий ввода-вывода в блоке do? Обратите внимание и на то, как выровнено выраже- ние let по отношению к действиям ввода-вывода и как выровнены образцы внутри выражения let. Это хороший пример, потому что выравнивание текста очень важно в языке Haskell. Далее мы запи- сали вызов map toUpper firstName, что превратит, например, "Иван" в намного более солидное "ИВАН". Мы связали эту строку в верхнем регистре с именем, которое использовали в дальнейшем при выво- де на терминал.
Вам может быть непонятно, когда использовать символ <–, а ког- да выражение let. Запомните: символ <– (в случае действий ввода- вывода) используется для выполнения действий ввода-вывода и свя- зывания результатов с именами. Выражение map toUpper firstName не является действием ввода-вывода – это чистое выражение. Со- ответственно, используйте символ <– для связывания результатов действий ввода-вывода с именами, а выражение let – для связыва- ния имён с чистыми значениями. Если бы мы выполнили что-то вроде let firstName = getLine, то просто создали бы синоним функ- ции getLine, для которого значение всё равно должно получаться с помощью символа <–.
Обращение строк Теперь напишем программу, которая будет считывать строки, пере- ставлять в обратном порядке буквы в словах и распечатывать их. Вы- полнение программы прекращается при вводе пустой строки. Итак: main = do line <– getLine if null line then return () else do putStrLn $ reverseWords line main
reverseWords:: String –> String reverseWords = unwords. map reverse. words Чтобы лучше понять, как работает программа, сохраните её в файле reverse.hs, скомпилируйте и запустите: $ ghc reverse.hs [1 of 1] Compiling Main (reverse.hs, reverse.o) Linking reverse... $./reverse уберитесь в проходе номер 9 ьсетиребу в едохорп ремон 9 козёл ошибки осветит твою жизнь лёзок икбишо титевсо юовт ьнзиж но это всё мечты он отэ ёсв ытчем
Для начала посмотрим на функцию reverseWords. Это обыч- ная функция, которая принимает строку, например "эй ты мужик", и вызывает функцию words, чтобы получить список слов ["эй", "ты","мужик"]. Затем мы применяем функцию reverse к каждому элементу списка, получаем ["йэ","ыт","кижум"] и помещаем ре- зультат обратно в строку, используя функцию unwords. Конечным результатом будет "йэ ыт кижум". Теперь посмотрим на функцию main. Сначала мы получаем стро- ку с терминала с помощью функции getLine. Далее у нас имеется условное выражение. Запомните, что в языке Haskell каждое клю- чевое слово if должно сопровождаться секцией else, так как каж- дое выражение должно иметь некоторое значение. Наш оператор записан так, что если условие истинно (в нашем случае – когда вве- дут пустую строку), мы выполним одно действие ввода-вывода; если оно ложно – выполним действие ввода-вывода из секции else. По той же причине в блоке do условные операторы if должны иметь вид if < условие > then < действие ввода-вывода > else < действие ввода- вывода >. Вначале посмотрим, что делается в секции else. Поскольку можно поместить только одно действие ввода-вывода после клю- чевого слова else, мы используем блок do для того, чтобы «склеить» несколько операторов в один. Эту часть можно было бы написать так: else (do putStrLn $ reverseWords line main) Подобная запись явно показывает, что блок do может рассмат- риваться как одно действие ввода-вывода, но и выглядит она не очень красиво. В любом случае внутри блока do мы можем вызвать функцию reverseWords со строкой – результатом действия getLine и распечатать результат. После этого мы выполняем функцию main. Получается, что функция main вызывается рекурсивно, и в этом нет ничего необычного, так как сама по себе функция main – тоже действие ввода-вывода. Таким образом, мы возвращаемся к началу программы в следующей рекурсивной итерации. Ну а что случится, если мы получим на вход пустую строку? В этом случае выполнится часть после ключевого слова then. То есть выпол- нится выражение return (). Если вам приходилось писать на импера-
тивных языках вроде C, Java или на Python, вы наверняка уверены, что знаете, как работает функция return – и, возможно, у вас воз- никнет искушение пропустить эту часть текста. Но не стоит спе- шить: функция return в языке Haskell работает совершенно не так, как в большинстве других языков! Её название сбивает с толку, но на самом деле она довольно сильно отличается от своих «тёзок». В императивных языках ключевое слово return обычно прекращает выполнение метода или процедуры и возвращает некоторое зна- чение вызывающему коду. В языке Haskell (и особенно в действиях ввода-вывода) одноимённая функция создаёт действие ввода-выво- да из чистого значения. Если продолжать аналогию с коробками, она берёт значение и помещает его в «коробочку». Получившееся в результате действие ввода-вывода на самом деле не выполняет ни- каких действий – оно просто инкапсулирует некоторое значение. Таким образом, в контексте системы ввода-вывода return "ха-ха" будет иметь тип IO String. Какой смысл преобразовывать чистое значение в действие ввода-вывода, которое ничего не делает? За- чем «пачкать» нашу программу больше необходимого? Нам нужно некоторое действие ввода-вывода для второй части условного опе- ратора, чтобы обработать случай пустой строки. Вот для чего мы создали фиктивное действие ввода-вывода, которое ничего не де- лает, записав return (). Вызов функции return не прекращает выполнение блока do – ничего подобного! Например, следующая программа успешно вы- полнится вся до последней строчки: main = do return () return "ХА-ХА-ХА" line <– getLine return "ЛЯ-ЛЯ-ЛЯ" return 4 putStrLn line Всё, что делает функция return, – создаёт действия ввода-выво- да, которые не делают ничего, кроме как содержат значения, и все они отбрасываются, поскольку не привязаны к образцам. Мы мо- жем использовать функцию return вместе с символом <– для того, чтобы связывать значения с образцами.
main = do let a = "ад" b = "да!" putStrLn $ a ++ " " ++ b Как вы можете видеть, функция return выполняет обратную операцию по отношению к операции <–. В то время как функция return принимает значение и помещает его в «коробку», операция <– принимает (и исполняет) «коробку», а затем привязывает получен- ное из неё значение к имени. Но всё это выглядит лишним, так как в блоках do можно использовать выражение let для привязки к име- нам, например так: main = do let a = "hell" b = "yeah" putStrLn $ a ++ " " ++ b При работе с блоками do мы чаще всего используем функцию return либо для создания действия ввода-вывода, которое ничего не делает, либо для того, чтобы блок do возвращал нужное нам зна- чение, а не результат последнего действия ввода-вывода. Во втором случае мы используем функцию return, чтобы создать действие вво- да-вывода, которое будет всегда возвращать нужное нам значение, и эта функция return должна находиться в самом конце блока do.
|
|||||||||||||||||||||||||||||||||||||
Последнее изменение этой страницы: 2017-02-17; просмотров: 194; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.216.57.57 (0.006 с.) |