2017-02-13 3 views
0
import   Control.Monad 
import   Control.Monad.Random  as MR 
import   Control.Monad.ST 
import qualified Data.Vector.Unboxed   as VU 
import qualified Data.Vector.Unboxed.Mutable as VUM 
import qualified Data.Vector     as V 
import qualified Data.Vector.Generic   as VG 
import   Data.Vector.Generic.Mutable as VGM 
import qualified Data.Vector.Unboxed   as VU 


data Obj m = Obj 
    { aNum :: Int 
    , vec :: m (VU.Vector Int) 
    } 

instance Show (Obj m) where 
    show Obj{ aNum = a 
      , vec = v 
      } = show a ++ show v -- 'show v' not OK 

main :: IO() 
main = do 
    rVec <- evalRandIO (randVector 5) -- OK 
    obj <- evalRandIO (newObj 1 5) -- Not OK 
    print $ show rVec 
    print $ show obj 

newObj :: (MonadRandom m) => Int -> Int -> Obj m 
newObj aNum' vecLen = Obj aNum' $ randVector vecLen 

randVector :: (MonadRandom m) => Int -> m (VU.Vector Int) 
randVector len = randSample (VU.enumFromN 0 len) $ VG.length vec 

-- Fisher-yates shuffle 
randSample :: (MonadRandom m, (VG.Vector v a)) => v a -> Int -> m (v a) 
randSample vec len = do 
    let getR i = do 
      r <- getRandomR (i, (VG.length vec)-1) 
      return (i, r) 

    swaps <- mapM getR [0..len-1] 

    let vec_rands = runST $ do 
      vec_mut <- VG.thaw vec 
      forM_ swaps $ \(i, j) -> do 
       VGM.swap vec_mut i j 
      vec_rands' <- VG.unsafeFreeze vec_mut 
      return vec_rands' 

    return $ VG.take len vec_rands 

Ich habe Probleme beim Erstellen von Datenstrukturen mit Monaden. Insbesondere enthält die Datenstruktur einen Zufallsvektor und einige andere Felder, die nicht zufällig sind. Die Verwendung von evalRandIO funktioniert, wenn der ganze Typ eine Monade ist, aber nicht, wenn nur ein Teil der Datenstruktur eine Monade ist. Ich habe das Gefühl, dass ich fmap oder etwas ähnliches verwenden sollte, aber sie geben andere Fehler. Ich habe auch Probleme, einen zufälligen Vektor in eine Zeichenfolge zu konvertieren, um sie auf dem Bildschirm zu drucken. Ich bin mir nicht sicher über den Unterschied zwischen Rand g und MonadRandom m, und welche ich verwenden sollte. Letztere scheinen zu funktionieren, aber alle Online-Beispiele scheinen stattdessen Rand g zu verwenden. Außerdem. Allgemeine Code-Überprüfung wird ebenfalls geschätzt.Datenstrukturen mit Monaden

* Couldn't match type `Obj m1' 
       with `RandT StdGen Data.Functor.Identity.Identity a0' 
    Expected type: Rand StdGen a0 
    Actual type: Obj m1 
* In the first argument of `evalRandIO', namely `(newObj 1 5)' 
    In a stmt of a 'do' block: obj <- evalRandIO (newObj 1 5) 
    In the expression: 
    do { rVec <- evalRandIO (randVector 5); 
     obj <- evalRandIO (newObj 1 5); 
     print $ show rVec } 
+0

'm (Vector Int)' ist keine Vektor- oder Datenstruktur. Warum hast du das 'm' drin? – melpomene

+0

Wenn ich nicht bekomme, bekomme ich Typ-Fehler beim Aufruf von 'randVector' in' newObj' – tsorn

+1

'newObj n vecLen = do {vec <- randVector vecLen; return (Obj n vec)} ' – melpomene

Antwort

4
newObj  :: (MonadRandom m) => Int -> Int -> Obj m 
newObj 1 4 :: (MonadRandom m) =>    Obj m 
evalRandIO ::         Rand StdGen a -> IO a          
evalRandIO (newObj 1 4) :: -- ????????? 

Das Problem ist, dass Obj m nicht Rand StdGen a ist. Daher können Sie evalRandIO nicht verwenden.

Allerdings macht es keinen Sinn, die m innerhalb Obj zu setzen. Es ist möglich, aber nicht wirklich praktisch. Wir könnten Ihren Code reparieren, wenn wir

evalObj :: Obj m -> IO (Int, (VU.Vector Int)) 
evalObj (Obj a mvec) = do 
    uvec <- evalRandIO mvec 
    return (a, uvec) 

verwendet haben Aber das ist immer noch nicht einfach zu bedienen. Stattdessen lassen Sie uns Obj vereinfachen:

data Obj = Obj { oNum :: Int, oVec :: VU.Vector Int } deriving (Eq, Show) 

Jetzt ist newObj umschreiben lassen, so dass es m Obj zurückgibt:

newObj :: (MonadRandom m) => Int -> Int -> m Obj 
newObj num len = Obj num `fmap` randVector len 

-- alternatively, but does the same: 
newObj num len = do 
    vec <- randVector len 
    return (Obj num vec) 

Und alles ist in Ordnung. Dies macht es auch möglich, Ihre Obj in Funktionen zu verwenden, die nicht wissen, dass Sie in einem MonadRandom, z.

sqObj :: Obj -> Obj 
sqObj (Obj a v) = Obj (a * a) (VU.map (^2) v) 
+0

In Bezug auf den letzten Punkt. Ist das nur möglich, wenn ein 'm Obj' in eine monadische Funktion eingebunden wurde? Wenn nicht, woher weiß ich dann, dass eine Funktion nicht weiß, dass sie in 'MonadRandom' arbeitet? Weil ich nicht in der Lage sein kann, 'MonadRandom m' von der Typ-Signatur von' randVector' zu entfernen, obwohl die Funktion selbst nichts von 'MonadRandom' verwendet. – tsorn