Нет fmap
означает, что вы можете отобразить над произвольным Functor
типом (хорошо подумайте об этом пока как о коллекции), но вы делаете это только один "уровень функтора" глубоко. В случае, если вы fmap
со списком, это в точности эквивалентно map
.
fmap
однако определяется для всех видов Functor
с, таких как списки, Maybe
с и т. Д. Здесь вы можете, таким образом, fmap
в fmap
отобразить два уровни:
fApplyFunctor = <b>fmap (fmap (+1))</b> [Just 1, Just 2]
Это приведет к:
Prelude> fmap (fmap (+1)) [Just 1, Just 2]
[Just 2,Just 3]
Prelude> (fmap (+1)) <$> [Just 1, Just 2]
[Just 2,Just 3]
Prelude> ((+1) <$>) <$> [Just 1, Just 2]
[Just 2,Just 3]
РЕДАКТИРОВАТЬ : как @ DanielWagner говорит, что существует тип данных Compose
, который работает над двумя (или более, если Вы каскад ) Functor
с и, таким образом, позволяет нам fmap
два уровня глубины. Это реализовано так:
newtype Compose f g a = Compose { getCompose :: f (g a) }
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose x) = Compose (fmap (fmap f) x)
поэтому здесь мы снова выполняем fmap
на двух уровнях:
Prelude Data.Functor.Compose> getCompose ((+1) <$> Compose [Just 1, Just 2])
[Just 2,Just 3]
Но, как вы видите, требуется некоторый синтаксис, чтобы сначала обернуть данные в Compose
, а затем позже "развернуть" их из Compose
, так что это также требует дополнительной работы.