Perché abbiamo map, fmap e 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

Perché abbiamo tre diverse funzioni che fanno essenzialmente la stessa cosa?


32
Storia, soprattutto. fmap è distinto da map per ragioni pedagogiche, liftM distinto da fmap per ragioni storiche (vale a dire Functor non è una superclasse di Monad)
luqui

12
Oh, e solo per il gusto di essere chiari: non fanno "essenzialmente" la stessa cosa. Entrambi mape liftMdovrebbero sicuramente fare esattamente la stessa cosa di fmap.
CA McCann

2
Mentre fmape liftMfanno esattamente la stessa cosa, mapovviamente è solo un caso speciale di loro, cioè qualcosa di diverso. fmap id getLineè ben digitato, mentre map id getLinenon lo è.
Thorsten

Risposte:


91

mapesiste per semplificare le operazioni sulle liste e per ragioni storiche (vedi Qual è lo scopo della mappa in Haskell, quando c'è fmap? ).

Potresti chiedere perché abbiamo bisogno di una funzione mappa separata. Perché non eliminare l'attuale funzione di mappa di sola lista e rinominare invece fmap in map? Bene, questa è una buona domanda. Il solito argomento è che qualcuno che sta imparando Haskell, quando usa map in modo errato, preferirebbe di gran lunga vedere un errore sugli elenchi piuttosto che su Functors.

- Typeclassopedia , pagina 20

fmaped liftMesistono perché le monadi non erano automaticamente funtori in Haskell:

Il fatto che abbiamo sia fmap che liftM è una sfortunata conseguenza del fatto che la classe di tipo Monad non richiede un'istanza di Functor, anche se matematicamente parlando, ogni monade è un funtore. Tuttavia, fmap e liftM sono essenzialmente intercambiabili, poiché è un bug (in senso sociale piuttosto che tecnico) per qualsiasi tipo essere un'istanza di Monad senza essere anche un'istanza di Functor.

- Typeclassopedia , pagina 33

Modifica: la storia di agustuss mape fmap:

In realtà non è così che succede. Quello che è successo è stato che il tipo di mappa è stato generalizzato per coprire Functor in Haskell 1.3. Cioè, in Haskell 1.3 fmap era chiamato map. Questa modifica è stata quindi ripristinata in Haskell 1.4 ed è stato introdotto fmap. La ragione di questo cambiamento era pedagogica; quando si insegnava Haskell ai principianti il ​​tipo molto generale di mappa rendeva i messaggi di errore più difficili da capire. Secondo me questo non era il modo giusto per risolvere il problema.

- Qual è il punto della mappa in Haskell, quando c'è fmap?


13
E, dal mio punto di vista come qualcuno che ha incontrato per la prima volta Haskell più di un decennio dopo il cambiamento descritto da @augustss, e ha trascorso molto tempo ad aiutare le persone che stanno imparando la lingua ora, non è affatto chiaro che abbia aiutato Comunque. Certamente non abbastanza per compensare l'inutile ridondanza (che a sua volta porta le persone a fare domande come questa); la Functorclasse è troppo comune per essere ignorata e i principianti sono spesso confusi comunque dai messaggi di errore!
CA McCann

10
Non possiamo semplicemente rimuovere liftM? Lascia che il codice si interrompa, chi se ne frega, di solito ci vogliono meno di 2 giorni perché il codice venga corretto su GitHub e quindi caricato su hackage. O sono pazzo e selvaggio?
Tarrasch

1
@Tarrasch: non tutti usano GitHub, non tutti i pacchetti hanno un ottimo track record per essere aggiornati in tempo, e io per primo tendo a usarlo liftMmentre sono in un blocco piuttosto che fmapperché si adatta meglio a quando lo uso liftM2, ecc. anche.
ivanm

1
@ L01man le persone hanno lavorato su questo; vedi stackoverflow.com/questions/5730270/… e almeno per le classi numeriche, ci sono alternative: hackage.haskell.org/packages/archive/numeric-prelude/0.3.0.2/…
li.davidm

1
@ L01man Sì, questo verrà presto risolto. La proposta di monade applicativa (AMP) sembra che passerà alla prossima versione di Haskell. GHC 7.8.3 ha un nuovo flag --fwarn-ampper aiutare ad aggiornare il codice esistente per la transizione.
recursion.ninja
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.