Warum haben wir map, fmap und liftM?


102
map :: (a -> b) -> [a] -> [b]

fmap :: Functor f => (a -> b) -> f a -> f b

liftM :: Monad m => (a -> b) -> m a -> m b

Warum haben wir drei verschiedene Funktionen, die im Wesentlichen dasselbe tun?


32
Meistens Geschichte. fmap unterscheidet sich aus pädagogischen Gründen von map, liftM unterscheidet sich aus historischen Gründen von fmap (nämlich Functor ist keine Superklasse von Monad)
luqui

12
Oh, und nur um klar zu sein: Sie tun nicht "im Wesentlichen" dasselbe. Beides mapund liftMsollte mit Sicherheit genau das Gleiche tun wie fmap.
CA McCann

2
Während fmapund liftMgenau das Gleiche tun, ist dies mapnatürlich nur ein Sonderfall, dh etwas anderes. fmap id getLineist gut getippt, wohingegen map id getLinees nicht ist.
Thorsten

Antworten:


91

mapexistiert, um Operationen an Listen und aus historischen Gründen zu vereinfachen (siehe Was ist der Sinn der Karte in Haskell, wenn es eine fmap gibt? ).

Sie fragen sich vielleicht, warum wir eine separate Kartenfunktion benötigen. Warum nicht einfach die aktuelle Nur-Listen-Kartenfunktion abschaffen und stattdessen fmap in map umbenennen? Das ist eine gute Frage. Das übliche Argument ist, dass jemand, der gerade Haskell lernt, bei falscher Verwendung der Karte lieber einen Fehler über Listen als über Functors sieht.

- Typeclassopedia , Seite 20

fmapund liftMexistieren, weil Monaden in Haskell nicht automatisch Funktoren waren:

Die Tatsache, dass wir sowohl fmap als auch liftM haben, ist eine unglückliche Folge der Tatsache, dass die Monad-Typklasse keine Functor-Instanz benötigt, obwohl mathematisch gesehen jede Monad ein Functor ist. Fmap und liftM sind jedoch im Wesentlichen austauschbar, da es ein Fehler (eher in sozialer als in technischer Hinsicht) ist, dass jeder Typ eine Instanz von Monad ist, ohne auch eine Instanz von Functor zu sein.

- Typeclassopedia , Seite 33

Edit: agustuss 'geschichte von mapund fmap:

So passiert es eigentlich nicht. Was passierte war, dass der Kartentyp verallgemeinert wurde, um Functor in Haskell 1.3 abzudecken. Dh in Haskell 1.3 wurde fmap map genannt. Diese Änderung wurde dann in Haskell 1.4 rückgängig gemacht und fmap wurde eingeführt. Der Grund für diese Änderung war pädagogisch; Wenn Anfängern Haskell beigebracht wurde, erschwerte der sehr allgemeine Kartentyp das Verstehen von Fehlermeldungen. Meiner Meinung nach war dies nicht der richtige Weg, um das Problem zu lösen.

- Was ist der Sinn der Karte in Haskell, wenn es eine Karte gibt?


13
Und aus meiner Sicht als jemand, der Haskell mehr als ein Jahrzehnt nach der von @augustss beschriebenen Änderung kennengelernt hat und viel Zeit damit verbracht hat, Menschen zu helfen, die die Sprache jetzt lernen, ist es überhaupt nicht klar, dass es überhaupt geholfen hat wie auch immer. Sicherlich nicht genug, um die nutzlose Redundanz auszugleichen (was selbst dazu führt, dass Leute Fragen wie diese stellen); Die FunctorKlasse ist zu häufig, um sie zu ignorieren, und Anfänger werden ohnehin oft durch Fehlermeldungen verwirrt!
CA McCann

10
Können wir nicht einfach entfernen liftM? Lassen Sie den Code brechen, wen interessiert das? Normalerweise dauert es weniger als 2 Tage, bis der Code auf Github repariert und dann bei Hackage hochgeladen wird. Oder bin ich wild und verrückt?
Tarrasch

1
@Tarrasch: Nicht jeder verwendet Github, nicht alle Pakete haben eine großartige Erfolgsbilanz, um rechtzeitig aktualisiert zu werden, und ich neige dazu, liftMsie eher in einem Do-Block zu verwenden, als fmapweil sie besser zu meiner Verwendung passen liftM2usw. auch.
ivanm

1
@ L01man Leute haben daran gearbeitet; siehe stackoverflow.com/questions/5730270/… und zumindest für numerische Klassen gibt es Alternativen: hackage.haskell.org/packages/archive/numeric-prelude/0.3.0.2/…
li.davidm

1
@ L01man Ja das wird bald behoben. Der Applicative Monad Proposal (AMP) scheint in die nächste Version von Haskell überzugehen. GHC 7.8.3 verfügt über ein neues Flag, --fwarn-ampmit dessen Hilfe der vorhandene Code für den Übergang aktualisiert werden kann.
recursion.ninja
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.