map scale
Mapa versus comportamiento de MapM (2)
Estoy en el capítulo I / O de Real World Haskell. Las mónadas no se discuten en el libro por otros 7 capítulos. Es decir, mi comprensión de E / S es, en el mejor de los casos, incompleta.
En este momento estoy tratando de comprender la función mapM. Como lo entiendo, la función "ejecuta" cada elemento de la lista, que debe ser una "acción" (mónada IO).
Lo que no tiene sentido es este ejemplo . ¿Por qué mapM devuelve un resultado diferente al mapa para los mismos argumentos?
Prelude> map (/x -> [x]) [0, 1, 2] [[0],[1],[2]] Prelude> mapM (/x -> [x]) [0, 1, 2] [[0,1,2]]
Como lo entiendo, la función "ejecuta" cada elemento de la lista, que debe ser una "acción" (mónada IO).
Eso es cierto para IO, pero en su ejemplo de código no usa la mónada IO, usa la mónada lista (la función que le da a mapM devuelve una lista ( [x]
), no una IO).
mapM
se define como mapM f as = sequence (map f as)
. Si f devuelve un IO, esto significa que para cada elemento de la lista construye un IO aplicando f al elemento. Luego convierte la lista de IO que el mapa devuelve en un IO que "contiene" una lista usando una secuencia (de modo que cuando ejecuta el IO, recupera una lista que contiene valores que no son IO).
Para listas significa que crea una lista de listas aplicando f
a cada elemento de as
. Luego utiliza la sequence
para crear una lista de listas que contiene todas las formas posibles de tomar un elemento de cada lista en las listas de listas (por ejemplo, la sequence [[1,2],[3,4]]
devuelve [[1,3],[1,4],[2,3],[2,4]]
).
Probablemente valga la pena aclarar que estos dos fragmentos no son "análogos" y que no debe esperar resultados relacionados. En particular, una versión ''monádica'' de
mapa (/ x -> [x]) [0, 1, 2]
es
mapM (/ x -> return [x]) [0, 1, 2]
Tenga en cuenta el return
adicional.
En general, return (map fx)
es lo mismo que mapM (return . f) x
.
Esto se debe a que para la lista mónada, x >>= f
''aplana'' el resultado de aplicar f
a x
. Cuando omitió la return
los resultados de la aplicación /x -> [x]
se estaban aplanando en el resultado. Tener un return
extra cancela el aplanamiento adicional.