2016-11-20 2 views
1

Wie verwenden Sie IO Double Werte aus dem globalen Zufallsgenerator in Haskell in arithmetischen und logischen Operationen? Die meisten Tutorials im Internet konzentrieren sich darauf, Zufallszahlen zu erhalten, aber irgendwie scheint ich nicht in der Lage zu sein, etwas Nützliches mit ihnen zu tun. Der folgende Code enthält eine Funktion test, die einige der Operationen enthält, die ich ausführen möchte.Verwenden von Zufallswerten aus dem globalen Zufallszahlengenerator in Haskell in arithmetischen und logischen Operationen

{-# LANGUAGE Strict #-} 
module RNG where 
import System.Random(setStdGen, mkStdGen, randomRIO) 

seed_rng :: Int -> IO() 
seed_rng seed = (setStdGen (mkStdGen seed)) 

uniform_float :: IO Double 
uniform_float = (randomRIO (0.0, 1.0)) 

test :: Double -> Double -> IO Double 
test a b = let u = (uniform_float) 
       in if ((<) (return a) u) then ((+) (return b) u) else (return 2.0) 

Die Testfunktion nicht kompiliert, da kein Beispiel für Ord (IO Double) und Num (IO Double) ist.

Beachten Sie, dass ich die IO Monad durch die Implementierung eines Zufallsgenerators und Tracking vermeiden kann + den Staat selbst übergeben. Aber ich lerne eher mit Monads zu arbeiten, anstatt immer davon wegzulaufen.

+0

Tangential Frage: gibt es einen bestimmten Grund, warum Sie verwenden '{- # SPRACHE Streng # -} '? – duplode

+1

@duplode Sehr leistungskritischer Code (praktisch nur Zahlen zerkleinern). Ich brauche eigentlich nie die Vorteile einer faulen Bewertung. – Matthias

+0

Okay, das hört sich vernünftig an. – duplode

Antwort

4

In einem monadischen Kontext können Sie do verwenden tatsächlich die Berechnung auszuführen:

test :: Double -> Double -> IO Double 
test a b = do 
    u <- uniform_float 
    if a < u 
     then return (b + u) 
     else return 2.0 

Die allgemeine Idee ist: <- verwenden, um vorübergehend ein Double aus einem IO Double zu extrahieren, und dann das Ergebnis innerhalb IO setzen mit return.

So fasst diese zwei einheitliche Zahlen:

sumTwo :: IO Double 
sumTwo = do 
    x <- uniform_float 
    y <- uniform_float 
    return (x+y) 

Es gibt Alternativen zu do, aber ich würde empfehlen, do zuerst lernen, da es ziemlich allgemein und einfach genug. Wenn Sie sich mehr an monadische Berechnungen, Anwendungen und Funktoren gewöhnt haben, werden Sie wahrscheinlich auch kompakte Alternativen wie sumTwo = (+) <$> uniform_float <*> uniform_float mögen.

+0

Vielen Dank funktioniert wie ein Charme! – Matthias

3

(>>=) kann verwendet werden, um eine zweite monadische Berechnung zu verketten, die die Werte Double verwendet.

test :: Double -> Double -> IO Double 
test a b = uniform_float >>= \u -> return (if a < u then b + u else 2.0) 

Eine alternative Art und Weise des oben für das Schreiben eines do-Block wird unter Verwendung von:

test :: Double -> Double -> IO Double 
test a b = do 
    u <- uniform_float 
    return (if a < u then b + u else 2.0) 

Schließlich, in denen in den Fällen, wie diese, die zweite monadischen Berechnung einfach Berechnung eine nicht-monadisch ist, gefolgt von einem return, brauchen Sie nicht einmal (>>=) - fmap ist genug:

test :: Double -> Double -> IO Double 
test a b = fmap (\u -> if a < u then b + u else 2.0) uniform_float 
Verwandte Themen