Миран Липовача - Изучай Haskell во имя добра!
- Название:Изучай Haskell во имя добра!
- Автор:
- Жанр:
- Издательство:ДМК Пресс
- Год:2012
- Город:Москва
- ISBN:978-5-94074-749-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Миран Липовача - Изучай Haskell во имя добра! краткое содержание
Язык Haskell имеет множество впечатляющих возможностей, но главное его свойство в том, что меняется не только способ написания кода, но и сам способ размышления о проблемах и возможных решениях. Этим Haskell действительно отличается от большинства языков программирования. С его помощью мир можно представить и описать нестандартным образом. И поскольку Haskell предлагает совершенно новые способы размышления о проблемах, изучение этого языка может изменить и стиль программирования на всех прочих.
Ещё одно необычное свойство Haskell состоит в том, что в этом языке придаётся особое значение рассуждениям о типах данных. Как следствие, вы помещаете больше внимания и меньше кода в ваши программы.
Вне зависимости от того, в каком направлении вы намерены двигаться, путешествуя в мире программирования, небольшой заход в страну Haskell себя оправдает. А если вы решите там остаться, то наверняка найдёте чем заняться и чему поучиться!
Эта книга поможет многим читателям найти свой путь к Haskell.
Отображения, монады, моноиды и другое! Всё сказано в названии: «Изучай Хаскель во имя добра!» – весёлый иллюстрированный самоучитель по этому сложному функциональному языку.
С помощью оригинальных рисунков автора, отсылке к поп-культуре, и, самое главное, благодаря полезным примерам кода, эта книга обучает основам функционального программирования так, как вы никогда не смогли бы себе представить.
Вы начнете изучение с простого материала: основы синтаксиса, рекурсия, типы и классы типов. Затем, когда вы преуспеете в основах, начнется настоящий мастер-класс от профессионала: вы изучите, как использовать аппликативные функторы, монады, застежки, и другие легендарные конструкции Хаскеля, о которых вы читали только в сказках.
Продираясь сквозь образные (и порой безумные) примеры автора, вы научитесь:
• Смеяться в лицо побочным эффектам, поскольку вы овладеете техниками чистого функционального программирования.
• Использовать волшебство «ленивости» Хаскеля для игры с бесконечными наборами данных.
• Организовывать свои программы, создавая собственные типы, классы типов и модули.
• Использовать элегантную систему ввода-вывода Хаскеля, чтобы делиться гениальностью ваших программ с окружающим миром.
Нет лучшего способа изучить этот мощный язык, чем чтение «Изучай Хаскель во имя добра!», кроме, разве что, поедания мозга его создателей. Миран Липовача (Miran Lipovača) изучает информатику в Любляне (Словения). Помимо его любви к Хаскелю, ему нравится заниматься боксом, играть на бас-гитаре и, конечно же, рисовать. У него есть увлечение танцующими скелетами и числом 71, а когда он проходит через автоматические двери, он притворяется, что на самом деле открывает их силой своей мысли.
Изучай Haskell во имя добра! - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
baseRect :: Float –> Float –> Shape
baseRect width height = Rectangle (Point 0 0) (Point width height)
Теперь создавать формы гораздо легче: достаточно создать форму в начале координат, а затем сдвинуть её в нужное место:
ghci> nudge (baseRect 40 100) 60 23
Rectangle (Point 60.0 23.0) (Point 100.0 123.0)
Фигуры на экспорт
Конечно же, вы можете экспортировать типы данных из модулей. Чтобы сделать это, запишите имена ваших типов вместе с именами экспортируемых функций. В отдельных скобках, через запятую, укажите, какие конструкторы значений вы хотели бы экспортировать. Если хотите экспортировать все конструкторы значений, просто напишите две точки (..)
.
Если бы мы хотели поместить функции и типы, определённые выше, в модуль, то могли бы начать как-то так:
module Shapes
( Point(..)
, Shape(..)
, area
, nudge
, baseCircle
, baseRect
) where
Запись Shape(..)
обозначает, что мы экспортируем все конструкторы данных для типа Shape
. Тот, кто импортирует наш модуль, сможет создавать фигуры, используя конструкторы Rectangle
и Circle
. Это то же самое, что и Shape (Rectangle, Circle)
, но короче.
К тому же, если мы позже решим дописать несколько конструкторов данных, перечень экспортируемых объектов исправлять не придётся. Всё потому, что конструкция ..
автоматически экспортирует все конструкторы соответствующего типа.
Мы могли бы не указывать ни одного конструктора для типа Shape
, просто записав Shape
в операторе экспорта. В таком случае тот, кто импортирует модуль, сможет создавать фигуры только с помощью функций baseCircle
и baseRect
.
Помните, конструкторы данных – это простые функции, принимающие поля как параметры и возвращающие значение некоторого типа (например, Shape
) как результат. Если мы их не экспортируем, то вне модуля они будут недоступны. Отказ от экспорта конструкторов данных делает наши типы данных более абстрактными, поскольку мы скрываем их реализацию. К тому же, пользователи нашего модуля не смогут выполнять сопоставление с образцом для этих конструкторов данных. Это полезно, если мы хотим, чтобы программисты, импортирующие наш тип, работали только со вспомогательными функциями, которые мы специально для этого написали. Таким образом, у них нет необходимости знать о деталях реализации модуля, и мы можем изменить эти детали, когда захотим – лишь бы экспортируемые функции работали как прежде.
Модуль Data.Map
использует такой подход. Вы не можете создать отображение напрямую при помощи соответствующего конструктора данных, потому что такой конструктор не экспортирован. Однако можно создавать отображения, вызвав одну из вспомогательных функций, например Map.fromList
. Разработчики, ответственные за Data.Map
, в любой момент могут поменять внутреннее представление отображений, и при этом ни одна существующая программа не сломается.
Разумеется, экспорт конструкторов данных для типов попроще вполне допустим.
Синтаксис записи с именованными полями

Есть ещё один способ определить тип данных. Предположим, что перед нами поставлена задача создать тип данных для описания человека. Данные, которые мы намереваемся хранить, – имя, фамилия, возраст, рост, телефон и любимый сорт мороженого. (Не знаю, как насчёт вас, но это всё, что я хотел бы знать о человеке!) Давайте опишем такой тип:
data Person = Person String String Int Float String String deriving (Show)
Первое поле – это имя, второе – фамилия, третье – возраст и т. д. И вот наш персонаж:
ghci> let guy = Person "Фредди" "Крюгер" 43 184.2 "526–2928" "Эскимо"
ghci> guy
Person "Фредди" "Крюгер" 43 184.2 "526–2928" "Эскимо"
Ну, в целом приемлемо, хоть и не очень «читабельно». Что если нам нужна функция для получения какого-либо поля? Функция, которая возвращает имя, функция для фамилии и т. д.? Мы можем определить их таким образом:
firstName :: Person –> String
firstName (Person firstname _ _ _ _ _) = firstname
lastName :: Person –> String
lastName (Person _ lastname _ _ _ _) = lastname
age :: Person –> Int
age (Person _ _ age _ _ _) = age
height :: Person –> Float
height (Person _ _ _ height _ _) = height
phoneNumber :: Person –> String
phoneNumber (Person _ _ _ _ number _) = number
flavor :: Person –> String
flavor (Person _ _ _ _ _ flavor) = flavor
Фу-ух! Мало радости писать такие функции!.. Этот метод очень громоздкий и скучный, но он работает.
ghci> let guy = Person "Фредди" "Крюгер" 43 184.2 "526–2928" "Эскимо"
ghci> firstName guy
"Фредди"
ghci> height guy
184.2
ghci> flavor guy
"Эскимо"
Вы скажете – должен быть лучший способ! Ан нет, извиняйте, нету… Шучу, конечно же. Такой метод есть! «Ха-ха» два раза. Создатели языка Haskell предусмотрели подобную возможность – предоставили ещё один способ для записи типов данных. Вот как мы можем достигнуть той же функциональности с помощью синтаксиса записей с именованными полями:
data Person = Person { firstName :: String
, lastName :: String
, age :: Int
, height :: Float
, phoneNumber :: String
, flavor :: String } deriving (Show)
Вместо того чтобы просто перечислять типы полей через запятую, мы используем фигурные скобки. Вначале пишем имя поля, например firstName
, затем ставим два двоеточия ::
и, наконец, указываем тип. Результирующий тип данных в точности такой же. Главная выгода – такой синтаксис генерирует функции для извлечения полей. Язык Haskell автоматически создаст функции firstName
, lastName
, age
, height
, phoneNumber
и flavor
.
ghci> :t flavor
flavor :: Person –> String
ghci> :t firstName
firstName :: Person –> String
Есть ещё одно преимущество в использовании синтаксиса записей. Когда мы автоматически генерируем экземпляр класса Show
для типа, он отображает тип не так, как если бы мы использовали синтаксис записей с именованными полями для объявления и инстанцирования типа. Например, у нас есть тип, представляющий автомобиль. Мы хотим хранить следующую информацию: компания-производитель, название модели и год производства.
data Car = Car String String Int deriving (Show)
Автомобиль отображается так:
ghci> Car "Форд" "Мустанг" 1967
Car "Форд" "Мустанг" 1967
Используя синтаксис записей с именованными полями, мы можем описать новый автомобиль так:
data Car = Car { company :: String
, model :: String
, year :: Int
} deriving (Show)
Автомобиль теперь создаётся и отображается следующим образом:
ghci> Car {company="Форд", model="Мустанг", year=1967}
Car {company = "Форд", model = "Мустанг", year = 1967}
При создании нового автомобиля мы, разумеется, обязаны перечислить все поля, но указывать их можно в любом порядке. Но если мы не используем синтаксис записей с именованными полями, то должны указывать их по порядку.
Читать дальшеИнтервал:
Закладка: