2010-07-01 30 views
7

¿Existe una forma tradicional de asignar una función que utiliza IO? Específicamente, me gustaría asignar una función que devuelva un valor aleatorio de algún tipo. Usar un mapa normal dará como resultado una salida de tipo ([IO b]), pero para descomprimir los valores en la lista de IO, necesito algo del tipo (IO [b]). Así que escribí ...Mapeo sobre IO en Haskell

mapIO :: (a -> IO b) -> [a] -> [b] -> IO [b] 
mapIO f [] acc = do return acc 
mapIO f (x:xs) acc = do 
    new <- f x 
    mapIO f xs (new:acc) 

... que funciona bien. Pero parece que debería haber una solución para esto integrada en Haskell. Por ejemplo, un ejemplo Caso de uso:

getPercent :: Int -> IO Bool 
getPercent x = do 
    y <- getStdRandom (randomR (1,100)) 
    return $ y < x 

mapIO (\f -> getPercent 50) [0..10] [] 
+9

En el futuro, pruebe [Hoogle] (http://haskell.org/hoogle/?hoogle= (a + -% 3E + IO + b \) + -% 3E + \ [a \] + -% 3E + IO + \ [b \]) para averiguar si ya existe alguna función aparentemente obvia (porque normalmente lo hacen). ¡Es asombrosamente útil! –

+0

¡Gracias, parece un gran recurso! – unignorant

+1

Además, echa un vistazo a Hayoo, es como Hoogle, pero verifica las cosas de forma ligeramente diferente. – BMeph

Respuesta

21

La forma estándar es a través de:

Control.Monad.mapM :: (Monad m) => (a -> m b) -> [a] -> m [b] 

que se implementa en términos de secuencia:

sequence :: (Monad m) => [m a] -> m [a] 
+0

Gracias! Exactamente lo que estaba buscando. – unignorant

+1

por cierto, 'mapM' ya está en Prelude – newacct

9

Sólo para añadir a la respuesta de Don, Eche un vistazo a la función mapM_ también, que hace exactamente lo que hace mapM pero descarta todos los resultados para que solo tenga efectos secundarios.

Esto es útil si desea tener los cálculos ejecutados (por ejemplo, cálculos IO) pero no están interesados ​​en el resultado (por ejemplo, desvinculación de archivos).

Y también vea forM y forM_.

+7

y mapM_ se ejecuta en un espacio de pila constante, mientras que mapM necesita una pila lineal, de forma similar para secuencia vs. secuencia. –

+0

@Simon, gracias por mencionar esto. Siempre miro mis mapas con mucho cuidado para asegurarme de que la lista sea pequeña o para tratar de refactorizar el uso de mapM_. –