2010-06-29 9 views
28

Estoy en el capítulo I/O de Real World Haskell. Las mónadas no se discuten en el libro para otros 7 capítulos. Lo que quiere decir que mi comprensión de E/S es, en el mejor de los casos, incompleta.mapa frente a comportamiento mapM

En este momento estoy tratando de comprender la función mapM. Según 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 this example. ¿Por qué MapM devuelve un resultado diferente que el 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]]
+0

también es divertido: 'longitud (mapM (\\ _-> a) b) == length a^length b'. Creo. – muhmuhten

Respuesta

18

Según tengo entendido, 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 el ejemplo de código no se utiliza la mónada IO, se utiliza la mónada lista (la función que le das a mapm devuelve una lista ([x]), no un 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 mapean los retornos en un IO que "contiene" una lista usando la secuencia (por lo que cuando ejecuta el IO, obtiene una lista que contiene valores que no son IO).

Para las listas, significa que crea una lista de listas al aplicar f a cada elemento de as. A continuación, usa 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, sequence [[1,2],[3,4]] devuelve [[1,3],[1,4],[2,3],[2,4]]).

+3

Para ampliar esto. A la luz de la definición de mapM, aplique el tipo de secuencia: sequence :: (Monad m) => [m a] -> m [a] con el ejemplo dado. mapM (\ x -> [x]) [0, 1, 2] = secuencia (mapa (\ x -> [x]) [0, 1, 2]) = secuencia [[0], [1] , [2]] = [[0,1,2]] –

+1

Matthew S: Su comentario fue muy útil, gracias. – titaniumdecoy

10

Probablemente valga la pena aclarar que estos dos fragmentos no son "análogos" y no debe esperar resultados relacionados. En particular, una versión 'monádico' de

mapa (\ x -> [x]) [0, 1, 2]

es

mapm (\ x - > return [x]) [0, 1, 2]

Tenga en cuenta el extra return.

En general, return (map f x) es lo mismo que mapM (return . f) x.

Esto se debe a que para la lista de mónada, x >>= f 'aplana' el resultado de aplicar f a x. Cuando omitió el return, los resultados de aplicar \x -> [x] se aplanaron en el resultado. Tener un extra return cancela el aplanamiento adicional.

Cuestiones relacionadas