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.
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.
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.
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.
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.
@ 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.
map
yliftM
ciertamente deberían hacer exactamente lo mismo quefmap
.fmap
yliftM
hacen exactamente lo mismo,map
por supuesto es solo un caso especial de ellos, es decir, algo diferente.fmap id getLine
está bien mecanografiado, mientrasmap id getLine
que no.Respuestas:
map
existe para simplificar las operaciones en listas y por razones históricas (consulte ¿Cuál es el punto de map en Haskell, cuando hay fmap? ).- Typeclassopedia , página 20
fmap
yliftM
existen porque las mónadas no eran functors automáticamente en Haskell:- Typeclassopedia , página 33
Editar: historia de agustuss
map
yfmap
:- ¿Cuál es el punto de map en Haskell, cuando hay fmap?
fuente
Functor
clase es demasiado común para ignorarla, ¡y los principiantes a menudo se confunden con los mensajes de error de todos modos!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?liftM
mientras estoy en un bloque de tareas en lugar de hacerlofmap
porque encaja mejor cuando lo usoliftM2
, etc. también.--fwarn-amp
para ayudar a actualizar el código existente para la transición.