2010-07-01 15 views
7

C'è un modo tradizionale per mappare su una funzione che utilizza IO? In particolare, mi piacerebbe mappare su una funzione che restituisce un valore casuale di qualche tipo. Usando una mappa normale si otterrà un output di tipo ([IO b]), ma per decomprimere i valori nella lista da IO, ho bisogno di qualcosa di tipo (IO [b]). Così ho scritto ...Mappatura su IO in 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) 

... che funziona bene. Ma sembra che ci dovrebbe essere una soluzione per questo costruito in Haskell. Per esempio, utilizzare un esempio caso:

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

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

In futuro, prova [Hoogle] (http://haskell.org/hoogle/?hoogle= (a + -% 3E + IO + b \) + -% 3E + \ [a \] + -% 3E + IO + \ [b \]) per scoprire se esiste già una funzione apparentemente ovvia (perché di solito lo fanno). È incredibilmente utile! –

+0

Grazie, sembra una grande risorsa! – unignorant

+1

Inoltre, controlla Hayoo - è come Hoogle, ma controlla le cose in modo leggermente diverso. – BMeph

risposta

21

Il modo standard è via:

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

che viene realizzato in termini di sequenza:

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

Grazie! Esattamente quello che stavo cercando. – unignorant

+1

a proposito, 'mapM' è già in Prelude – newacct

9

Giusto per aggiungere alla risposta di Don, Dai un'occhiata alla funzione mapM_, che fa esattamente ciò che mapM ma elimina tutti i risultati in modo da ottenere solo effetti collaterali.

Questo è utile se si desidera eseguire i calcoli eseguiti (ad esempio calcoli IO) ma non sono interessati al risultato (ad esempio, scollegamento di file).

E vedere anche forM e forM_.

+7

e mapM_ viene eseguito nello spazio di stack costante, mentre mapM richiede lo stack lineare, analogamente per sequenza_ vs. sequenza. –

+0

@Simon, grazie per aver menzionato questo. Osservo sempre con attenzione la mia mappaM per accertarmi che la lista sia piccola o per cercare di ridefinire l'uso di mapM_. –