Kann liftM unterscheiden sich von lifta?
-
06-07-2019 - |
Frage
Nach der Typeclassopedia (neben anderen Quellen), Applicative
logisch gehört zwischen Monad
und Pointed
(und damit Functor
) in der Art Klassenhierarchie, so dass wir im Idealfall etwas davon haben, wenn der Haskell Auftakt heute geschrieben wurde:
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Functor f => Pointed f where
pure :: a -> f a
class Pointed f => Applicative f where
(<*>) :: f (a -> b) -> f a -> f b
class Applicative m => Monad m where
-- either the traditional bind operation
(>>=) :: (m a) -> (a -> m b) -> m b
-- or the join operation, which together with fmap is enough
join :: m (m a) -> m a
-- or both with mutual default definitions
f >>= x = join ((fmap f) x)
join x = x >>= id
-- with return replaced by the inherited pure
-- ignoring fail for the purposes of discussion
(Wo diese Standarddefinitionen wurden von mir neu eingegeben von der Erklärung bei Wikipedia , wobei Fehler meine eigenen, aber wenn es Fehler gibt, ist es zumindest prinzipiell möglich.)
Da die Bibliotheken derzeit definiert sind, haben wir:
liftA :: (Applicative f) => (a -> b) -> f a -> f b
liftM :: (Monad m) => (a -> b) -> m a -> m b
und
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
ap :: (Monad m) => m (a -> b) -> m a -> m b
Beachten Sie die Ähnlichkeit zwischen diesen Arten in jedem Paar.
Meine Frage ist: ist liftM
(im Unterschied zu liftA
) und ap
(im Unterschied zu <*>
), einfach ein Ergebnis der historischen Realität, dass Monad
nicht mit Pointed
und Applicative
konzipiert wurde? Oder sind sie in irgendeiner anderen Art und Weise Verhaltens (möglicherweise für einige rechtliche Monad
Definitionen) unterscheiden sich von den Versionen, die nur einen Applicative
Kontext erfordern?
Wenn sie verschieden sind, könnten Sie einen einfachen Satz von Definitionen zur Verfügung stellen (die Gesetze zu gehorchen erforderlich von Monad
, Applicative
, Pointed
und Functor
Definitionen in der Typeclassopedia beschrieben und an anderer Stelle aber nicht vom Typ System erzwungen), für die liftA
und liftM
anders verhalten?
Alternativ kann, wenn sie nicht eindeutig sind, können Sie beweisen ihre Gleichwertigkeit die gleichen Gesetze wie Räumlichkeiten mit?
Lösung
liftA
, liftM
, fmap
und .
sollte alle die gleiche Funktion sein, und sie muss , wenn sie das Funktors Gesetz erfüllen:
fmap id = id
Dies ist jedoch nicht geprüft von Haskell.
Jetzt für Applicative. Es ist möglich, für ap
und <*>
für einige functors einfach verschieden zu sein, weil es mehr als eine Implementierung sein könnten, die die Typen und die Gesetze erfüllen. Zum Beispiel hat Liste mehr als eine mögliche Applicative
Instanz. Sie könnten eine applicative erklären, wie folgt:
instance Applicative [] where
(f:fs) <*> (x:xs) = f x : fs <*> xs
_ <*> _ = []
pure = repeat
Die ap
Funktion würde immer noch als liftM2 id
definiert werden, die die Applicative
Instanz ist, die mit jedem Monad
kostenlos kommt. Aber hier haben Sie ein Beispiel für einen Typkonstruktor mehr als eine Applicative
Instanz, die beide von denen die Gesetze erfüllen. Aber wenn Ihr Monaden und Ihre applicative functors nicht einverstanden ist, ist es zum guten Ton für sie verschiedene Typen haben. Zum Beispiel ist das Applicative
Beispiel oben nicht mit der Monade für []
einverstanden ist, so sollten Sie wirklich newtype ZipList a = ZipList [a]
sagen und dann die neue Instanz für ZipList
statt []
machen.
Andere Tipps
Sie können unterscheiden, aber sie sollte nicht .
können Sie unterscheiden, da sie unterschiedliche Implementierungen haben kann: Die eine ist in einem instance Applicative
definiert, während die andere in einem instance Monad
definiert ist. Aber wenn sie in die Tat unterschiedlich ist, dann würde ich die Programmierer sagt, wer diese Instanzen schrieb schrieben Code irreführend.
Sie haben Recht: Die Funktionen existieren, wie sie aus historischen Gründen tun. Die Menschen haben starke Ideen darüber, wie die Dinge gewesen sein sollte.