¿Por qué tenemos map, fmap y 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

¿Por qué tenemos tres funciones diferentes que hacen esencialmente lo mismo?


32
Historia, sobre todo. fmap es diferente de map por razones pedagógicas, liftM es diferente de fmap por razones históricas (es decir, Functor no es una superclase de
Monad

12
Ah, y por el simple hecho de ser claro: no hacen "esencialmente" lo mismo. Ambos mapy liftMciertamente deberían hacer exactamente lo mismo que fmap.
CA McCann

2
Si bien fmapy liftMhacen exactamente lo mismo, mappor supuesto es solo un caso especial de ellos, es decir, algo diferente. fmap id getLineestá bien mecanografiado, mientras map id getLineque no.
Thorsten

Respuestas:


91

mapexiste para simplificar las operaciones en listas y por razones históricas (consulte ¿Cuál es el punto de map en Haskell, cuando hay fmap? ).

Puede preguntar por qué necesitamos una función de mapa separada. ¿Por qué no simplemente eliminar la función de mapa actual de solo lista y cambiar el nombre de fmap a mapa en su lugar? Bueno, esa es una buena pregunta. El argumento habitual es que alguien que acaba de aprender Haskell, cuando usa el mapa incorrectamente, preferiría ver un error sobre las listas que sobre los Functors.

- Typeclassopedia , página 20

fmapy liftMexisten porque las mónadas no eran functors automáticamente en Haskell:

El hecho de que tengamos fmap y liftM es una consecuencia desafortunada del hecho de que la clase de tipo Monad no requiere una instancia de Functor, aunque matemáticamente hablando, cada mónada es un functor. Sin embargo, fmap y liftM son esencialmente intercambiables, ya que es un error (en un sentido social más que técnico) que cualquier tipo sea una instancia de Monad sin ser también una instancia de Functor.

- Typeclassopedia , página 33

Editar: historia de agustuss mapy fmap:

En realidad, no es así como sucede. Lo que sucedió fue que el tipo de mapa se generalizó para cubrir Functor en Haskell 1.3. Es decir, en Haskell 1.3 fmap se llamaba map. Este cambio luego se revirtió en Haskell 1.4 y se introdujo fmap. La razón de este cambio fue pedagógica; Al enseñar Haskell a principiantes, el tipo de mapa muy general hizo que los mensajes de error fueran más difíciles de entender. En mi opinión, esta no era la forma correcta de resolver el problema.

- ¿Cuál es el punto de map en Haskell, cuando hay fmap?


13
Y, desde mi perspectiva como alguien que se encontró por primera vez con Haskell más de una década después de que se hizo el cambio que describe @augustss, y ha pasado mucho tiempo ayudando a las personas que están aprendiendo el idioma ahora, no está del todo claro que incluso haya ayudado en de todas formas. Ciertamente, no lo suficiente para compensar la redundancia inútil (que en sí misma lleva a que la gente haga preguntas como ésta); la Functorclase es demasiado común para ignorarla, ¡y los principiantes a menudo se confunden con los mensajes de error de todos modos!
CA McCann

10
¿No podemos simplemente eliminar liftM? Deje que el código se rompa, a quién le importa, generalmente se necesitan menos de 2 días para que el código se corrija en github y luego se cargue en el pirateo. ¿O estoy siendo salvaje y loco?
Tarrasch

1
@Tarrasch: no todo el mundo usa github, no todos los paquetes tienen un gran historial de actualización a tiempo y, por mi parte, suelo usarlo liftMmientras estoy en un bloque de tareas en lugar de hacerlo fmapporque encaja mejor cuando lo uso liftM2, etc. también.
ivanm

1
La gente de @ L01man ha trabajado en esto; ver stackoverflow.com/questions/5730270/… y al menos para clases numéricas, hay alternativas: hackage.haskell.org/packages/archive/numeric-prelude/0.3.0.2/…
li.davidm

1
@ L01man Sí, esto se solucionará pronto. La propuesta de mónada aplicativa (AMP) parece que pasará a la próxima versión de Haskell. GHC 7.8.3 tiene una nueva marca --fwarn-amppara ayudar a actualizar el código existente para la transición.
recursión.ninja
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.