Миран Липовача - Изучай Haskell во имя добра!
- Название:Изучай Haskell во имя добра!
- Автор:
- Жанр:
- Издательство:ДМК Пресс
- Год:2012
- Город:Москва
- ISBN:978-5-94074-749-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Миран Липовача - Изучай Haskell во имя добра! краткое содержание
Язык Haskell имеет множество впечатляющих возможностей, но главное его свойство в том, что меняется не только способ написания кода, но и сам способ размышления о проблемах и возможных решениях. Этим Haskell действительно отличается от большинства языков программирования. С его помощью мир можно представить и описать нестандартным образом. И поскольку Haskell предлагает совершенно новые способы размышления о проблемах, изучение этого языка может изменить и стиль программирования на всех прочих.
Ещё одно необычное свойство Haskell состоит в том, что в этом языке придаётся особое значение рассуждениям о типах данных. Как следствие, вы помещаете больше внимания и меньше кода в ваши программы.
Вне зависимости от того, в каком направлении вы намерены двигаться, путешествуя в мире программирования, небольшой заход в страну Haskell себя оправдает. А если вы решите там остаться, то наверняка найдёте чем заняться и чему поучиться!
Эта книга поможет многим читателям найти свой путь к Haskell.
Отображения, монады, моноиды и другое! Всё сказано в названии: «Изучай Хаскель во имя добра!» – весёлый иллюстрированный самоучитель по этому сложному функциональному языку.
С помощью оригинальных рисунков автора, отсылке к поп-культуре, и, самое главное, благодаря полезным примерам кода, эта книга обучает основам функционального программирования так, как вы никогда не смогли бы себе представить.
Вы начнете изучение с простого материала: основы синтаксиса, рекурсия, типы и классы типов. Затем, когда вы преуспеете в основах, начнется настоящий мастер-класс от профессионала: вы изучите, как использовать аппликативные функторы, монады, застежки, и другие легендарные конструкции Хаскеля, о которых вы читали только в сказках.
Продираясь сквозь образные (и порой безумные) примеры автора, вы научитесь:
• Смеяться в лицо побочным эффектам, поскольку вы овладеете техниками чистого функционального программирования.
• Использовать волшебство «ленивости» Хаскеля для игры с бесконечными наборами данных.
• Организовывать свои программы, создавая собственные типы, классы типов и модули.
• Использовать элегантную систему ввода-вывода Хаскеля, чтобы делиться гениальностью ваших программ с окружающим миром.
Нет лучшего способа изучить этот мощный язык, чем чтение «Изучай Хаскель во имя добра!», кроме, разве что, поедания мозга его создателей. Миран Липовача (Miran Lipovača) изучает информатику в Любляне (Словения). Помимо его любви к Хаскелю, ему нравится заниматься боксом, играть на бас-гитаре и, конечно же, рисовать. У него есть увлечение танцующими скелетами и числом 71, а когда он проходит через автоматические двери, он притворяется, что на самом деле открывает их силой своей мысли.
Изучай Haskell во имя добра! - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Используйте синтаксис записей с именованными полями, если конструктор имеет несколько полей и не очевидно, какое поле для чего используется. Если, скажем, мы создаём трёхмерный вектор: data Vector = Vector Int Int Int
, то вполне понятно, что поля конструктора данных – это компоненты вектора. Но в типах Person
и Car
назначение полей совсем не так очевидно, и мы значительно выиграем, используя синтаксис записей с именованными полями.
Параметры типа
Конструктор данных может принимать несколько параметров-значений и возвращать новое значение. Например, конструктор Car
принимает три значения и возвращает одно – экземпляр типа Car
. Таким же образом конструкторы типа могут принимать типы-параметры и создавать новые типы. На первый взгляд это несколько абстрактно, но на самом деле не так уж сложно. Если вы знакомы с шаблонами в языке С++, то увидите некоторые параллели. Чтобы получить более ясное представление о том, как работают типы-параметры, давайте посмотрим, как реализованы типы, с которыми мы уже встречались.
data Maybe a = Nothing | Just a

В данном примере идентификатор a
– тип-параметр (переменная типа, типовая переменная). Так как в выражении присутствует тип-параметр, мы называем идентификатор Maybe
конструктором типов. В зависимости от того, какой тип данных мы хотим сохранять в типе Maybe
, когда он не Nothing
, конструктор типа может производить такие типы, как Maybe Int
, Maybe Car
, Maybe String
и т. д. Ни одно значение не может иметь тип «просто Maybe
», потому что это не тип как таковой – это конструктор типов. Для того чтобы он стал настоящим типом, значения которого можно создать, мы должны указать все типы-параметры в конструкторе типа.
Итак, если мы передадим тип Char
как параметр в тип Maybe
, то получим тип Maybe Char
. Для примера: значение Just 'a'
имеет тип Maybe Char
.
Обычно нам не приходится явно передавать параметры конструкторам типов, поскольку в языке Haskell есть вывод типов. Поэтому когда мы создаём значение Just 'a'
, Haskell тут же определяет его тип – Maybe Char
.
Если мы всё же хотим явно указать тип как параметр, это нужно делать в типовой части выражений, то есть после символа ::
. Явное указание типа может понадобиться, если мы, к примеру, хотим, чтобы значение Just 3
имело тип Maybe Int
. По умолчанию Haskell выведет тип (Num a) => Maybe a
. Воспользуемся явным аннотированием типа:
ghci> Just 3 :: Maybe Int
Just 3
Может, вы и не знали, но мы использовали тип, у которого были типы-параметры ещё до типа Maybe
. Этот тип – список. Несмотря на то что дело несколько скрывается синтаксическим сахаром, конструктор списка принимает параметр для того, чтобы создать конкретный тип. Значения могут иметь тип [Int]
, [Char]
, [[String]]
, но вы не можете создать значение с типом []
.
ПРИМЕЧАНИЕ.Мы называем тип конкретным, если он вообще не принимает никаких параметров (например, Int
или Bool
) либо если параметры в типе заполнены (например, Maybe Char
). Если у вас есть какое-то значение, у него всегда конкретный тип.
Давайте поиграем с типом Maybe
:
ghci> Just "Ха-ха"
Just "Ха-ха"
ghci> Just 84
Just 84
ghci> :t Just "Ха-ха"
Just "Ха-ха" :: Maybe [Char]
ghci> :t Just 84
Just 84 :: (Num t) => Maybe t
ghci> :t Nothing
Nothing :: Maybe a
ghci> Just 10 :: Maybe Double
Just 10.0
Типы-параметры полезны потому, что мы можем с их помощью создавать различные типы, в зависимости от того, какой тип нам надо хранить в нашем типе данных. К примеру, можно объявить отдельные Maybe-подобные типы данных для любых типов:
data IntMaybe = INothing | IJust Int
data StringMaybe = SNothing | SJust String
data ShapeMaybe = ShNothing | ShJust Shape
Более того, мы можем использовать типы-параметры для определения самого обобщённого Maybe
, который может содержать данные вообще любых типов!
Обратите внимание: тип значения Nothing
– Maybe a
. Это полиморфный тип: в его имени присутствует типовая переменная – конкретнее, переменная a
в типе Maybe a
. Если некоторая функция принимает параметр типа Maybe Int
, мы можем передать ей значение Nothing
, так как оно не содержит значения, которое могло бы этому препятствовать. Тип Maybe a
может вести себя как Maybe Int
, точно так же как значение 5
может рассматриваться как значение типа Int
или Double
. Аналогичным образом тип пустого списка – это [a]
. Пустой список может вести себя как список чего угодно. Вот почему можно производить такие операции, как [1,2,3] ++ []
и ["ха","ха","ха"] ++ []
.
Параметризовать ли машины?
Когда имеет смысл применять типовые параметры? Обычно мы используем их, когда наш тип данных должен уметь сохранять внутри себя любой другой тип, как это делает Maybe a
. Если ваш тип – это некоторая «обёртка», использование типов-параметров оправданно. Мы могли бы изменить наш тип данных Car
с такого:
data Car = Car { company :: String
, model :: String
, year :: Int
} deriving (Show)
на такой:
data Car a b c = Car { company :: a
, model :: b
, year :: c
} deriving (Show)
Но выиграем ли мы в чём-нибудь? Ответ – вероятно, нет, потому что впоследствии мы всё равно определим функции, которые работают с типом Car String String Int
. Например, используя первое определение Car
, мы могли бы создать функцию, которая отображает свойства автомобиля в виде понятного текста:
tellCar :: Car –> String
tellCar (Car {company = c, model = m, year = y}) =
"Автомобиль " ++ c ++ " " ++ m ++ ", год: " ++ show y
ghci> let stang = Car {company="Форд", model="Мустанг", year=1967}
ghci> tellCar stang
"Автомобиль Форд Мустанг, год: 1967"
Приятная маленькая функция. Декларация типа функции красива и понятна. А что если Car
– это Car a b c
?
tellCar :: (Show a) => Car String String a –> String
tellCar (Car {company = c, model = m, year = y}) =
"Автомобиль " ++ c ++ " " ++ m ++ ", год: " ++ show y
Мы вынуждены заставить функцию принимать параметр Car
типа (Show a) => Car String String a
. Как видите, декларация типа функции более сложна; единственное преимущество, которое здесь имеется, – мы можем использовать любой тип, имеющий экземпляр класса Show
, как тип для типовой переменной c
.
ghci> tellCar (Car "Форд" "Мустанг" 1967)
"Автомобиль Форд Мустанг, год: 1967"
ghci> tellCar (Car "Форд" "Мустанг" "тысяча девятьсот шестьдесят седьмой")
"Автомобиль Форд Мустанг, год: \"тысяча девятьсот шестьдесят седьмой\""
Интервал:
Закладка: