2016-05-16 20 views
2

Ich versuche, einen Zufallsgenerator in einer runST Anweisung zu verwenden und den Generator nach Gebrauch zurückzugeben, so kann es an anderer Stelle verwendet werden.Rückkehr Zufallsgenerator aus runST

Wenn ich nur einen Vektor zurückgeben, kompiliert der Code, aber wenn der Generator auf die Return-Anweisung das Hinzufügen der Kompilierung fehlschlägt. Wenn ich die Fehlermeldung richtig verstehe, heißt es, dass die Funktion, die an die monadische Falte übergeben wird, den Vektor nicht im selben Zustand verändert, aber ich kann nicht herausfinden, warum sie dann kompiliert, wenn ich den Zufallsgenerator aus der return-Anweisung weglasse.

Dies kompiliert:

import   Control.Monad 
import   Control.Monad.ST 
import qualified Data.Vector.Unboxed   as VU 
import qualified Data.Vector.Unboxed.Mutable as VUM 
import   System.Random 

randVector :: (RandomGen g) => Int -> g -> VU.Vector Int 
randVector n g = runST $ do 
    vector <- VU.unsafeThaw (VU.enumFromN 1 n) 
    let step g i = do let (j,g') = randomR (1,n) g 
        VUM.swap vector i j 
        return g' 
    g' <- foldM step g [1..VUM.length vector-1] 
    VU.unsafeFreeze vector 

Aber dies nicht:

randVector' :: (RandomGen g) => Int -> g -> (VU.Vector Int, g) 
randVector' n g = runST $ do 
    vector <- VU.unsafeThaw (VU.enumFromN 1 n) :: ST s (VUM.MVector s Int) 
    let step g i = do let (j,g') = randomR (1,n) g 
        VUM.swap vector i j 
        return g' 
    g' <- foldM step g [1..VUM.length vector-1] 
    (VU.unsafeFreeze vector, g') 

Die return-Anweisung mit dem gefrorenen Vektor und dem Zufallsgenerator erzeugt den folgenden Fehler:

Couldn't match expected type ST s (VU.Vector Int, g) with actual type (m0 (VU.Vector Int), g)

Antwort

2

Blick auf der Art der unsafeFreeze: ein einzelnes Paar mit Typ zurückzukehren ST s (VU.Vector Int, g)

Stattdessen bindet den gefrorenen Vektor und return verwenden.

unsafeFreeze :: (Unbox a, PrimMonad m) => MVector (PrimState m) a -> m (Vector a) 

Es ist eine monadische Berechnung, die m (Vector a) zurückgibt. So hat der Ausdruck (VU.unsafeFreeze vector, g') eine Art (m (Vector Int), g). Der Typ-Checker sagt Ihnen, dass es nicht diese Art mit der Art des do Block vereinigen kann, was Sie sein ST s (Vector Int, g) erklärt.

Um diese Arten vereinigen zu machen, müssen wir die m aus dem Inneren des Tupels nach außen verteilen; dann wird der Typüberprüfer auf m ~ ST s schließen. Sie müssen die Vector aus ihrer monadischen Berechnung extrahieren und sie dann mit dem Generator sichern.

do 
    ... 
    v <- VU.unsafeFreeze vector 
    return (v, g') 
2

VU.unsafeFreeze vector gibt einen Vektor in einigen Monaden zurück (in diesem Fall ST s) . Denken Sie daran, dass jede Aktion in der gleichen Monade in einem do Ausdruck sein muss. Da (VU.unsafeFreeze vector, g') Typ nicht von ST s <something> ist, funktioniert es nicht mit runST.

g' <- ... 
    v' <- VU.unsafeFreeze vector 
    return (v', g')