- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Изучай Haskell во имя добра! - Миран Липовача
Шрифт:
Интервал:
Закладка:
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.
Некоторые полезные функции для ввода-вывода
В стандартной библиотеке языка Haskell имеется масса полезных функций и действий ввода-вывода. Давайте рассмотрим некоторые из них и увидим, как ими пользоваться.
Функция putStr
Функция putStr похожа на функцию putStrLn – она принимает строку как параметр и возвращает действие ввода-вывода, которое печатает строку на терминале. Единственное отличие: функция putStr не выполняет перевод на новую строку после печати, как это делает putStrLn.
main = do
putStr "Привет, "
putStr "я "
putStrLn "Энди!"
Если мы скомпилируем эту программу, то при запуске получим:
Привет, я Энди!
Функция putChar
Функция putChar принимает символ и возвращает действие ввода-вывода, которое напечатает его на терминале.
main = do
putChar 'A'
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

