2012-02-25 13 views
6

Necesito ejecutar una función que toma dos argumentos varias veces. Tengo dos listas que contienen estos argumentos y me gustaría poder usar map o algo similar para llamar a la función con los argumentos correspondientes.Uso del mapa con dos listas en lugar de una. ¿Puedes anidar?

La función Quiero llamar tiene este tipo:

runParseTest :: String -> String -> IO() 

Las listas se crean de esta manera:

-- Get list of files in libraries directory 
files <- getDirectoryContents "tests/libraries" 
-- Filter out ".." and "." and add path 
let names = filter (\x -> head x /= '.') files 
let libs = ["tests/libraries/" ++ f | f <- names] 

lo que permite decir que names contiene ["test1.js", "test2.js", "test3.js"] y libs contiene ["tests/libraries/test1.js", "tests/libraries/test2.js", "tests/libraries/test3.js"]

Quiero llamarlos así:

runParseTest "test1.js" "tests/libraries/test1.js" 
runParseTest "test2.js" "tests/libraries/test2.js" 
runParseTest "test3.js" "tests/libraries/test3.js" 

Sé que podría crear una función de ayuda que hace esto bastante fácilmente, pero por interés, ¿es posible hacerlo en una línea usando map?

Esto es lo que tengo hasta ahora, pero es evidente que el primer argumento es siempre "prueba":

mapM_ (runParseTest "test") libs 

Me disculpo si esto no está claro. Puedo proporcionar más información si es necesario.

Respuesta

10

lo que permite decir que los nombres contiene ["test1.js", "test2.js", "test3.js"] y libs contiene ["tests/libraries/test1.js", "tests/libraries/test2.js", "tests/libraries/test3.js"]

quiero llamarlos así:

runParseTest "test1.js" "tests/libraries/test1.js" runParseTest "test2.js" "tests/libraries/test2.js" runParseTest "test3.js" "tests/libraries/test3.js"

Es posible hacer eso con zip:

map (\(a,b) -> runParseTest a b) $ zip names libs 

O tal uncurry runParseTest:

map (uncurry runParseTest) $ zip names libs 

O con zipWith:

zipWith runParseTest names libs 

Y como Ozgur Dicho esto, hay algunos análogos de mónadas:

> :t zipWithM 
zipWithM :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c] 
> :t zipWithM_ 
zipWithM_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m() 
+0

Esto es lo que estaba buscando. De hecho, he escrito una nueva función llamada 'map2M_' que voy a publicar, pero esta es la forma" correcta "de hacerlo, estoy seguro. –

3

Usted busca zipWithM_.

Dice que podría escribir una función de ayuda que hace esto. Lo que significa que sabes el tipo de función que estás buscando. En tales casos, puede usar hoogle.

(Probar: Monad m => [a] -> [b] -> m())

15

Este es un buen momento para utilizar Hoogle!Hoogle es un motor de búsqueda para buscar Haskell tipos. Por ejemplo, una consulta de Hoogle para (a -> b) -> [a] -> [b] se detiene map. Aquí tiene una función del tipo String -> String -> IO(); quieres una función del tipo (String -> String -> IO()) -> [String] -> [String] -> IO(). Hoogle a menudo puede generalizar por sí mismo, pero está teniendo problemas aquí, así que vamos a ayudarlo: solo quiere (a -> a -> IO()) -> [a] -> [a] -> IO() para cualquier a. Si Hoogle for that type signature, el primer resultado es zipWithM_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m() en el módulo Control.Monad, que hace exactamente lo que desea. Esto es parte de una familia de funciones, con diversos grados de generalidad:

Así, en su caso de uso específico, vamos a tener, con algunos cambios adicionales -el siguientes:

import Data.List (isPrefixOf) 

... 

-- I got rid of `head` because it's a partial function, and I prefer `map` to 
-- list comprehensions for simple things  
do files <- getDirectoryContents "tests/libraries" 
    let names = filter (not . ("." `isPrefixOf`)) files 
     libs = map ("tests/libraries/" ++) names 
    zipWithM_ runParseTest names libs 
1

A la espera de respuestas que creó una solución de mi propio con una nueva función llamada map2M_ basado en el código fuente de map y mapM_:

map2 :: (a -> b -> c) -> [a] -> [b] -> [c] 
map2 _ [] _   = [] 
map2 _ _ []   = [] 
map2 f (a:as) (b:bs) = f a b : map2 f as bs 

map2M_ :: Monad m => (a -> b -> m c) -> [a] -> [b] -> m() 
map2M_ f as bs = sequence_ (map2 f as bs) 
Cuestiones relacionadas