2011-03-07 21 views
16

¿Qué hace concatMap? Sé lo que concat y map do. ¿Están ambos juntos o es una función completamente diferente?¿Qué hace concatMap?

+6

Comportamentalmente no se puede distinguir de 'concatMap f = concat. mapa f'. No estoy seguro de que sea teóricamente más eficiente tampoco. Es solo una combinación conveniente, supongo. – luqui

+2

@luqui Como 'concatMap' se implementa mediante' foldr', se puede optimizar utilizando la técnica 'foldr/build'. Por lo tanto, sí, es más eficiente: https://ghc.haskell.org/trac/ghc/wiki/FoldrBuildNotes –

Respuesta

8

Conceptualmente sí, pero el actual implementation es diferente:

concatMap    :: (a -> [b]) -> [a] -> [b] 
concatMap f    = foldr ((++) . f) [] 
+1

Podría ser útil indicar por qué 'concatMap' se implementa con' foldr', siendo el motivo cortar la deforestación usando la técnica 'foldr/build': https://ghc.haskell.org/trac/ghc/wiki/FoldrBuildNotes –

8

Comprobación the documentation revela:

concatMap :: (a -> [b]) -> [a] -> [b] 

mapear una función sobre una lista y concatenar los resultados

Y que su definición es así:

-- | Map a function over a list and concatenate the results. 
concatMap    :: (a -> [b]) -> [a] -> [b] 
concatMap f    = foldr ((++) . f) [] 

comparar la siguiente salida de ghci:

*Main> concatMap (++"! ") ["one", "two", "three"] 
"one! two! three! " 
*Main> concat $ map (++"! ") ["one", "two", "three"] 
"one! two! three! " 
+4

Además, si se está preguntando * por qué * existe, creo que es porque es la implementación de la lista de '>> =', acaba de dar un nombre diferente. :) – porges

14

Sí, la función concatMap es sólo concat y map juntos. De ahí el nombre. Poner juntas las funciones simplemente significa componer:

(.) :: (b -> c) -> (a -> b) -> a -> c 

Sin embargo concat y map no se pueden poner juntos por el simple uso de la composición de funciones debido a la firma de tipo de map:

map :: (a -> b) -> [a] -> [b] 
     -------- --- --- 
      a   b  c 

Como se puede ver la composición de funciones espera una función del tipo a -> b, pero map es del tipo a -> b -> c.Para componer concat con map es necesario utilizar el operador .: lugar:

(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d 

La función concat tiene una firma tipo de:

concat :: [[a]] -> [a] 
      ----- --- 
      c  d 

Por lo tanto concat .: map es de tipo:

concat .: map :: (a -> [b]) -> [a] -> [b] 
       ---------- --- --- 
        a   b  d 

Que es el mismo que el de concatMap:

concatMap :: (a -> [b]) -> [a] -> [b] 

El operador .: sí se puede escribir en términos de composición de funciones:

(.:) = (.) (.) (.) 

-- or 

(.:) = (.) . (.) 

Por lo tanto concatMap se puede escribir como:

concatMap = (.) (.) (.) concat map 

-- or 

concatMap = (concat .) . map 

-- or 

concatMap = concat .: map 

Si usted flip los argumentos de concatMap se obtiene el >>= (enlace) función de la lista mónada:

instance Monad [] where 
    return x = [x] 
    (>>=) = flip concatMap 
    fail _ = [] 

flip concatMap :: [a] -> (a -> [b]) -> [b] 

>>= :: Monad m => m a -> (a -> m b) -> m b 

Esto hace que sea la misma que la función de la lista =<< mónada:

concatMap :: (a -> [b]) -> [a] -> [b] 

=<< :: Monad m => (a -> m b) -> m a -> m b 

Así que ya saben todo lo que hay que saber sobre concatMap. Solo se aplica concat al resultado de map. De ahí el nombre.

+0

Excelente respuesta. Solo un error tipográfico: "** En ** volteas [...]" debería ser ** Si **. – YoTengoUnLCD