2010-07-01 17 views
7

Gibt es eine traditionelle Möglichkeit, eine Funktion, die IO verwendet, zuzuordnen? Insbesondere möchte ich eine Funktion zuordnen, die einen zufälligen Wert zurückgibt. Die Verwendung einer normalen Map führt zu einer Ausgabe vom Typ ([IO b]), aber um die Werte in der Liste von IO zu entpacken, brauche ich etwas vom Typ (IO [b]). Also schrieb ich ...Mapping über 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) 

... was gut funktioniert. Aber es scheint, dass es eine Lösung dafür in Haskell eingebaut geben sollte. Zum Beispiel kann ein Beispielfall verwenden:

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

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

Probieren Sie in Zukunft [Hoogle] (http://haskell.org/hoogle/?hoogle= (a + -% 3E + IO + b \) + -% 3E + \ [a \] + -% 3E + IO + \ [b \]), um herauszufinden, ob eine scheinbar offensichtliche Funktion bereits existiert (weil sie es normalerweise tut). Es ist unglaublich nützlich! –

+0

Danke, das sieht nach einer tollen Ressource aus! – unignorant

+1

Schauen Sie sich auch Hayoo an - es ist wie Hoogle, aber die Dinge werden etwas anders überprüft. – BMeph

Antwort

21

Der übliche Weg ist über:

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

, die in Bezug auf die Reihenfolge implementiert:

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

Danke! Genau das, was ich gesucht habe. – unignorant

+1

Übrigens ist 'mapM' bereits in Prelude – newacct

9

Nur um Don Antwort hinzuzufügen, Schauen Sie sich auch die mapM_ Funktion an, die genau das tut, was mapM tut, aber alle Ergebnisse verwirft, so dass Sie nur Nebenwirkungen bekommen.

Dies ist nützlich, wenn die Berechnungen ausgeführt werden sollen (z. B. E/A-Berechnungen), aber nicht am Ergebnis interessiert sind (z. B. das Aufheben der Verknüpfung von Dateien).

Und auch siehe forM und forM_.

+7

und mapM_ läuft im konstanten Stack Space, während mapM einen linearen Stack benötigt, ähnlich wie bei sequence_ vs. sequence. –

+0

@Simon, danke für das Erwähnen. Ich schaue mir meine mapMs immer sehr genau an, um sicherzustellen, dass entweder die Liste klein ist oder um zu versuchen, mapM_ zu refaktorieren. –