Was spricht, ist die Zusammensetzung der Typkonstruktoren wie []
und Maybe
, nicht die Zusammensetzung von Funktionen wie fmap
.So zum Beispiel, gibt es zwei Möglichkeiten der Komposition []
und Maybe
:
newtype ListOfMabye a = ListOfMaybe [Maybe a]
newtype MaybeOfList a = MaybeOfList (Maybe [a])
Die Aussage, dass die Zusammensetzung von zwei Functors
ist ein Functor
bedeutet, dass es eine formelhafte Art und Weise eine Functor
Beispiel für diese Art des Schreibens:
instance Functor ListOfMaybe where
fmap f (ListOfMaybe x) = ListOfMaybe (fmap (fmap f) x)
instance Functor MaybeOfList where
fmap f (MaybeOfList x) = MaybeOfList (fmap (fmap f) x)
In der Tat kommt die Haskell-Plattform mit dem Modul Data.Functor.Compose
, dass Sie eine Compose
Art gibt, die diese „kostenlos“ tut:
import Data.Functor.Compose
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)
Compose
ist besonders nützlich bei der GeneralizedNewtypeDeriving
extension:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype ListOfMaybe a = ListOfMaybe (Compose [] Maybe a)
-- Now we can derive Functor and Applicative instances based on those of Compose
deriving (Functor, Applicative)
anzumerken, dass die Zusammensetzung von zwei Applicative
s ist auch eine Applicative
. Daher sind, da []
und Maybe
Applicative
sind, auch Compose [] Maybe
und ListOfMaybe
. Komponieren Applicative
s ist eine wirklich nette Technik, die sich heutzutage immer mehr verbreitet, als eine Alternative zu Monade-Transformatoren für Fälle, in denen Sie nicht die volle Leistung von Monaden benötigen.
Haben Sie versucht, fmap mit sich selbst in Ghci zu komponieren? d.h. ': t fmap. fmap' – Squidly
@MrBones Danke für den Tipp! Für diejenigen, die keinen Ghci-Zugriff haben, ist die Ausgabe ':: (Functor f1, Functor f) => (a -> b) -> f (f1 a) -> f (f1 b)' – akbiggs