Мы уже встречали множество классов типов из стандартной библиотеки. Ознакомились с классом >Ord
, предусмотренным для сущностей, которые можно упорядочить. Вдоволь набаловались с классом >Eq
, предназначенным для сравнения на равенство. Изучили класс >Show
, предоставляющий интерфейс для типов, которые можно представить в виде строк. Наш добрый друг класс >Read
помогает, когда нам надо преобразовать строку в значение некоторого типа. Ну а теперь приступим к рассмотрению класса типов >Functor
, предназначенного для типов, которые могут быть отображены друг в друга.
Возможно, в этот момент вы подумали о списках: ведь отображение списков – это очень распространённая идиома в языке Haskell. И вы правы: списковый тип имеет экземпляр для класса >Functor
.
Нет лучшего способа изучить класс типов >Functor
, чем посмотреть, как он реализован. Вот и посмотрим:
>fmap :: (a -> b) -> f a -> f b
Итак, что у нас имеется? Класс определяет одну функцию >fmap
и не предоставляет для неё реализации по умолчанию. Тип функции >fmap
весьма интересен. Во всех вышеприведённых определениях классов типов тип-параметр, игравший роль типа в классе, был некоторого конкретного типа, как переменная >a
в сигнатуре >(==) :: (Eq a) => a –> a –> Bool
. Но теперь тип-параметр >f
не имеет конкретного типа (нет конкретного типа, который может принимать переменная, например >Int
, >Bool
или >Maybe String
); в этом случае переменная – конструктор типов, принимающий один параметр. (Напомню: выражение >Maybe Int
является конкретным типом, а идентификатор >Maybe
– конструктор типов с одним параметром.) Мы видим, что функция >fmap
принимает функцию из одного типа в другой и функтор, применённый к одному типу, и возвращает функтор, применённый к другому типу.
Если это звучит немного непонятно, не беспокойтесь. Всё прояснится, когда мы рассмотрим несколько примеров.
Гм-м… что-то мне напоминает объявление функции >fmap
! Если вы не знаете сигнатуру функции >map
, вот она:
>map :: (a –> b) –> [a] –> [b]
О, как интересно! Функция >map
берёт функцию из >a
в >b
и список элементов типа >a
и возвращает список элементов типа >b
. Друзья, мы только что обнаружили функтор! Фактически функция >map
– это функция >fmap
, которая работает только на списках. Вот как список сделан экземпляром класса >Functor
:
>instance Functor [] where
> fmap = map
И всё! Заметьте, мы не пишем