2016-04-09 18 views
1

Also mache ich ein bisschen mit Haskell herum, versuche es selbst zu lernen. Ich versuche eine bestimmte Frage zu lösen, wo ich eine Liste von Zufallszahlen erstellen und dann zusammenfassen soll.Eine Liste von IO Float zusammenfassen: [IO Float] in Haskell

Ich habe den Code, um sie zu generieren - mit getStdRandom und randomR. Mit ihnen beiden gibt eine Liste von IO Float: [IO Float]

Nun, wenn ich versuche, die Liste zusammenzufassen mit sagen foldl oder foldr oder sogar eine einfache Rekursion Summierung versuchen, erhalte ich Fehler und so - zu meinem Verständnis ist dies, weil IO Float ist eine Monade, also muss ich etwas Haskell-Magie machen, um es zum Laufen zu bringen.

Ich habe gegoogled und habe nichts gefunden, was funktioniert.

Gibt es eine Möglichkeit, die Liste zusammenzufassen? oder es sogar in eine Liste von Fließkommazahlen umwandeln, so dass es einfacher ist, in anderen Teilen des Codes zu arbeiten?

+0

fügen Sie bitte den Code, den Sie haben - die Lösung könnte so einfach sein wie 'Summe <$> whateverYouHaveNow' – Carsten

Antwort

9

Beachten Sie, dass eine Liste mit dem Typ [IO Float]nicht eine Liste von Zahlen ist. Es handelt sich um eine Liste von E/A-Aktionen, die Nummern generieren. Die E/A wurde noch nicht ausgeführt, daher hat der Zufallsgenerator in Ihrem Fall die Nummern nicht erzeugt.

können Sie verwenden, um die sequence :: Monad m => [m a] -> m [a] Funktion die Liste der IO Aktionen in eine einzige IO Aktion zu kombinieren, die eine Liste der Ergebnisse liefern:

do the_numbers <- sequence your_list 
    return $ sum the_numbers 

Alternativ könnten Sie die foldM Funktion verwenden, um ein einstelliges fach zu schreiben:

sumIONumbers :: [IO Float] -> IO Float 
sumIONumbers xs = foldM f 0.0 xs 
    where 
    f acc mVal = do 
     val <- mVal -- extract the Float from the IO 
     return $ acc + val 

Wie in den Kommentaren darauf hingewiesen, können Sie dort auch die Tatsache, dass jeder Monad auch ist ein Functor (dies in neueren Versionen erzwungen wird) und daher kann man fmap :: Functor f => (a -> b) -> f a -> f b verwenden, um eine Funktion innerhalb des IO anwenden:

fmap sum (sequence your_list) 

Oder das Infix Synonym verwenden <$>:

sum <$> sequence your_list 
+3

Diese erste 'do'-Anweisung könnte vereinfacht werden zu' fmap sum (sequence yourList) 'oder' sum <$> sequence yourList'. (Wobei ['fmap :: Functor f => (a -> b) -> fa -> fb]] (http://hackage.haskell.org/package/base-4.8.2.0/docs/Prelude.html# v: fmap) und '(<$>) = fmap') – AJFarmar

+0

OK Cool, thx. Ich denke, ich kann es von hier aus nehmen :) – user475680

+2

"** nicht ** eine Liste von Zahlen" - genau. Eine einfache Möglichkeit, dies zu sehen, ist die mehrfache Auswertung von 'sequence your_list': Sie erhalten jedes Mal ein anderes Ergebnis! – leftaroundabout

1

Wie wäre es so etwas wie die mit liftM folgenden:

import System.Random 
import Control.Monad 

rnd :: IO Float 
rnd = getStdRandom (randomR (0.0,1.0)) 

main = do 
    let l = map (\_ -> rnd) [1..10] 
    n <- foldl (liftM2 (+)) (return (0 :: Float)) l 
    print n