Миран Липовача - Изучай Haskell во имя добра! Страница 11

Тут можно читать бесплатно Миран Липовача - Изучай Haskell во имя добра!. Жанр: Компьютеры и Интернет / Программирование, год -. Так же Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте «WorldBooks (МирКниг)» или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.
Миран Липовача - Изучай Haskell во имя добра!

Миран Липовача - Изучай Haskell во имя добра! краткое содержание

Прочтите описание перед тем, как прочитать онлайн книгу «Миран Липовача - Изучай Haskell во имя добра!» бесплатно полную версию:
На взгляд автора, сущность программирования заключается в решении проблем. Программист всегда думает о проблеме и возможных решениях – либо пишет код для выражения этих решений.Язык Haskell имеет множество впечатляющих возможностей, но главное его свойство в том, что меняется не только способ написания кода, но и сам способ размышления о проблемах и возможных решениях. Этим Haskell действительно отличается от большинства языков программирования. С его помощью мир можно представить и описать нестандартным образом. И поскольку Haskell предлагает совершенно новые способы размышления о проблемах, изучение этого языка может изменить и стиль программирования на всех прочих.Ещё одно необычное свойство Haskell состоит в том, что в этом языке придаётся особое значение рассуждениям о типах данных. Как следствие, вы помещаете больше внимания и меньше кода в ваши программы.Вне зависимости от того, в каком направлении вы намерены двигаться, путешествуя в мире программирования, небольшой заход в страну Haskell себя оправдает. А если вы решите там остаться, то наверняка найдёте чем заняться и чему поучиться!Эта книга поможет многим читателям найти свой путь к Haskell.Отображения, монады, моноиды и другое!Всё сказано в названии: «Изучай Хаскель во имя добра!» – весёлый иллюстрированный самоучитель по этому сложному функциональному языку.С помощью оригинальных рисунков автора, отсылке к поп-культуре, и, самое главное, благодаря полезным примерам кода, эта книга обучает основам функционального программирования так, как вы никогда не смогли бы себе представить.Вы начнете изучение с простого материала: основы синтаксиса, рекурсия, типы и классы типов. Затем, когда вы преуспеете в основах, начнется настоящий мастер-класс от профессионала: вы изучите, как использовать аппликативные функторы, монады, застежки, и другие легендарные конструкции Хаскеля, о которых вы читали только в сказках.Продираясь сквозь образные (и порой безумные) примеры автора, вы научитесь:• Смеяться в лицо побочным эффектам, поскольку вы овладеете техниками чистого функционального программирования.• Использовать волшебство «ленивости» Хаскеля для игры с бесконечными наборами данных.• Организовывать свои программы, создавая собственные типы, классы типов и модули.• Использовать элегантную систему ввода-вывода Хаскеля, чтобы делиться гениальностью ваших программ с окружающим миром.Нет лучшего способа изучить этот мощный язык, чем чтение «Изучай Хаскель во имя добра!», кроме, разве что, поедания мозга его создателей.Миран Липовача (Miran Lipovača) изучает информатику в Любляне (Словения). Помимо его любви к Хаскелю, ему нравится заниматься боксом, играть на бас-гитаре и, конечно же, рисовать. У него есть увлечение танцующими скелетами и числом 71, а когда он проходит через автоматические двери, он притворяется, что на самом деле открывает их силой своей мысли.

Миран Липовача - Изучай Haskell во имя добра! читать онлайн бесплатно

Миран Липовача - Изучай Haskell во имя добра! - читать книгу онлайн бесплатно, автор Миран Липовача

Теперь, когда мы знаем, как использовать сопоставление с образцом для списков, давайте создадим собственную реализацию функции head:

head' :: [a] –> a

head' [] = error "Нельзя вызывать head на пустом списке, тупица!"

head' (x:_) = x

Проверим, работает ли это…

ghci> head' [4,5,6]

4

ghci> head' "Привет"

H'

Отлично! Заметьте, что если вы хотите выполнить привязку к нескольким переменным (даже если одна из них обозначена всего лишь символом _ и на самом деле ни с чем не связывается), вам необходимо заключить их в круглые скобки. Также обратите внимание на использование функции error. Она принимает строковый параметр и генерирует ошибку времени исполнения, используя этот параметр для сообщения о причине ошибки.

Вызов функции error приводит к аварийному завершению программы, так что не стоит использовать её слишком часто. Но вызов функции head на пустом списке не имеет смысла.

Давайте напишем простую функцию, которая сообщает нам о нескольких первых элементах списка – в довольно неудобной, чересчур многословной форме.

tell :: (Show a) => [a] –> String

tell [] = "Список пуст"

tell (x:[]) = "В списке один элемент: " ++ show x

tell (x:y:[]) = "В списке два элемента: " ++ show x ++ " и " ++ show y

tell (x:y:_) = "Список длинный. Первые два элемента: " ++ show x

                ++ " и " ++ show y

Обратите внимание, что образцы (x:[]) и (x:y:[]) можно записать как [x] и [x,y]. Но мы не можем записать (x:y:_) с помощью квадратных скобок, потому что такая запись соответствует любому списку длиной два или более.

Вот несколько примеров использования этой функции:

ghci> tell [1]

"В списке один элемент: 1"

ghci> tell [True, False]

"В списке два элемента: True и False"

ghci> tell [1, 2, 3, 4]

"Список длинный. Первые два элемента: 1 и 2"

ghci> tell []

"Список пуст"

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

А что если определить функцию, которая умеет обрабатывать только списки с тремя элементами? Вот один такой пример:

badAdd :: (Num a) => [a] -> a

badAdd (x:y:z:[]) = x + y + z

А вот что случится, если подать ей не то, что она ждёт:

ghci> badAdd [100, 20]

*** Exception: Non-exhaustive patterns in function badAdd

Это не так уж и хорошо. Если подобное случится в скомпилированной программе, то она просто вылетит.

И последнее замечание относительно сопоставления с образцами для списков: в образцах нельзя использовать операцию ++ (напомню, что это объединение двух списков). К примеру, если вы попытаетесь написать в образце (xs++ys), то Haskell не сможет определить, что должно попасть в xs, а что в ys. Хотя и могут показаться логичными сопоставления типа (xs++[x,y,z]) или даже (xs ++ [x]), работать это не будет – такова природа списков[7].

Именованные образцы

Ещё одна конструкция называется именованным образцом. Это удобный способ разбить что-либо в соответствии с образцом и связать результат разбиения с переменными, но в то же время сохранить ссылку на исходные данные. Такую задачу можно выполнить, поместив некий идентификатор образца и символ @ перед образцом, описывающим структуру данных. Например, так выглядит образец [email protected](x:y:ys).

Подобный образец работает так же, как (x:y:ys), но вы легко можете получить исходный список по имени xs, вместо того чтобы раз за разом печатать x:y:ys в теле функции. Приведу пример:

firstLetter :: String –> String

firstLetter "" = "Упс, пустая строка!"

firstLetter [email protected](x:xs) = "Первая буква строки " ++ all ++ " это " ++ [x]

Загрузим эту функцию и посмотрим, как она работает:

ghci> firstLetter "Дракула"

"Первая буква строки Дракула это Д"

Эй, стража!

В то время как образцы – это способ убедиться, что значение соответствует некоторой форме, и разобрать его на части, сторожевые условия (охрана, охранные выражения) – это способ проверить истинность некоторого свойства значения или нескольких значений, переданных функции. Тут можно провести аналогию с условным выражением if: оно работает схожим образом. Однако охранные выражения гораздо легче читать, если у вас имеется несколько условий; к тому же они отлично работают с образцами.

Вместо того чтобы объяснять их синтаксис, давайте просто напишем функцию с использованием охранных условий. Эта простая функция будет оценивать вас на основе ИМТ (индекса массы тела). Ваш ИМТ равен вашему весу, разделённому на квадрат вашего роста.

Если ваш ИМТ меньше 18,5, можно считать вас тощим. Если ИМТ составляет от 18,5 до 25, ваш вес в пределах нормы. От 25 до 30 – вы полненький; более 30 – тучный. Запишем эту функцию (мы не будем рассчитывать ИМТ, функция принимает его как параметр и ругнёт вас соответственно).

bmiTell :: Double -> String

bmiTell bmi

  | bmi <= 18.5 = "Слышь, эмо, ты дистрофик!"

  | bmi <= 25.0 = "По части веса ты в норме. Зато, небось, уродец!"

  | bmi <= 30.0 = "Ты толстый! Сбрось хоть немного веса!"

  | otherwise = "Мои поздравления, ты жирный боров!"

Охранные выражения обозначаются вертикальными чёрточками после имени и параметров функции. Обычно они печатаются с отступом вправо и начинаются с одной позиции. Охранное выражение должно иметь тип Bool. Если после вычисления условие имеет значение True, используется соответствующее тело функции. Если вычисленное условие ложно, проверка продолжается со следующего условия, и т. д.

Если мы вызовем эту функцию с параметром 24.3, она вначале проверит, не является ли это значение меньшим или равным 18.5. Так как охранное выражение на данном значении равно False, функция перейдёт к следующему варианту. Проверяется следующее условие, и так как 24.3 меньше, чем 25.0, будет возвращена вторая строка.

Это очень напоминает большие деревья условий if – else в императивных языках программирования – только такой способ записи значительно лучше и легче для чтения. Несмотря на то что большие деревья условий if – else обычно не рекомендуется использовать, иногда задача представлена в настолько разрозненном виде, что просто невозможно обойтись без них. Охранные выражения – прекрасная альтернатива для таких задач.

Во многих случаях последним охранным выражением является otherwise («иначе»). Значение otherwise определяется просто: otherwise = True; такое условие всегда истинно. Работа условий очень похожа на то, как работают образцы, но образцы проверяют входные данные, а охранные выражения могут производить любые проверки.

Если все охранные выражения ложны (и при этом мы не записали otherwise как последнее условие), вычисление продолжается со следующей строки определения функции. Вот почему сопоставление с образцом и охранные выражения так хорошо работают вместе. Если нет ни подходящих условий, ни клозов, будет сгенерирована ошибка времени исполнения.

Конечно же, мы можем использовать охранные выражения с функциями, которые имеют столько входных параметров, сколько нам нужно. Вместо того чтобы заставлять пользователя вычислять свой ИМТ перед вызовом функции, давайте модифицируем её так, чтобы она принимала рост и вес и вычисляла ИМТ:

bmiTell :: Double -> Double -> String

bmiTell weight height

  | weight / height ^ 2 <= 18.5 = "Слышь, эмо, ты дистрофик!"

  | weight / height ^ 2 <= 25.0 = "По части веса ты в норме.

                                   Зато, небось, уродец!"

  | weight / height ^ 2 <= 30.0 = "Ты толстый!

                                   Сбрось хоть немного веса!"

  | otherwise = "Мои поздравления, ты жирный боров!"

Ну-ка проверим, не толстый ли я…

ghci> bmiTell 85 1.90

"По части веса ты в норме. Зато, небось, уродец!"

Ура! По крайней мере, я не толстый! Правда, Haskell обозвал меня уродцем. Ну, это не в счёт.

ПРИМЕЧАНИЕ. Обратите внимание, что после имени функции и её параметров нет знака равенства до первого охранного выражения. Многие новички ставят этот знак, что приводит к ошибке.

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

max' :: (Ord a) => a –> a –> a

Перейти на страницу:
Вы автор?
Жалоба
Все книги на сайте размещаются его пользователями. Приносим свои глубочайшие извинения, если Ваша книга была опубликована без Вашего на то согласия.
Напишите нам, и мы в срочном порядке примем меры.
Комментарии / Отзывы
    Ничего не найдено.