Изучай Haskell во имя добра! (Липовача) - страница 109

, потому что из определения функции

>fmap :: (a –> b) –> f a –> f b

мы видим, что параметр >f должен быть конструктором типов, принимающим один тип. Выражение >[a] – это уже конкретный тип (список элементов типа >a), а вот >[] – это конструктор типов, который принимает один тип; он может производить такие конкретные типы, как >[Int], >[String] или даже >[[String]].

Так как для списков функция >fmap – это просто >map, то мы получим одинаковые результаты при их использовании на списках:

>map :: (a –> b) –> [a] –> [b]

>ghci>fmap (*2) [1..3]

>[2,4,6]

>ghci> map (*2) [1..3]

>[2,4,6]

Что случится, если применить функцию >map или >fmap к пустому списку? Мы получим опять же пустой список. Но функция >fmap преобразует пустой список типа >[a] в пустой список типа >[b].

Экземпляр класса Functor для типа Maybe

Типы, которые могут вести себя как контейнеры по отношению к другим типам, могут быть функторами. Можно представить, что списки – это коробки с бесконечным числом отсеков; все они могут быть пустыми, или же один отсек заполнен, а остальные пустые, или несколько из них заполнены. А что ещё умеет быть контейнером для других типов? Например, тип >Maybe. Он может быть «пустой коробкой», и в этом случае имеет значение >Nothing, или же в нём хранится какое-то одно значение, например >"ХА-ХА", и тогда он равен >Just>"ХА-ХА".

Вот как тип >Maybe сделан функтором:

>instance Functor Maybe where

>   fmap f (Just x) = Just (f x)

>   fmap f Nothing = Nothing

Ещё раз обратите внимание на то, как мы записали декларацию >instance Functor Maybe where вместо >instance Functor (Maybe m) where – подобно тому как мы делали для класса >YesNo. Функтор принимает конструктор типа с одним параметром, не конкретный тип. Если вы мысленно замените параметр >f на >Maybe, функция >fmap работает как >(a –> b) –> Maybe a –> Maybe b, только для типа >Maybe, что вполне себя оправдывает. Но если заменить >f на >(Maybe m), то получится >(a –> b) –> Maybe m a –> Maybe m b, что не имеет никакого смысла, так как тип >Maybe принимает только один тип-параметр.

Как бы то ни было, реализация функции >fmap довольно проста. Если значение типа >Maybe – это >Nothing, возвращается >Nothing. Если мы отображаем «пустую коробку», мы получим «пустую коробку», что логично. Точно так же функция >map для пустого списка возвращает пустой список. Если это не пустое значение, а некоторое значение, упакованное в конструктор >Just, то мы применяем функцию к содержимому >Just:

>ghci> fmap (++ " ПРИВЕТ, Я ВНУТРИ JUST") (Just "Серьёзная штука.")

>Just "Серьёзная штука. ПРИВЕТ, Я ВНУТРИ JUST"

>ghci> fmap (++ " ПРИВЕТ, Я ВНУТРИ JUST") Nothing