2017-02-13 12 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 

У меня возникли проблемы с созданием структур данных с монадами. В частности, структура данных содержит случайный вектор и некоторые другие поля, которые не являются случайными. Использование evalRandIO работает, когда весь тип является монадой, но не тогда, когда только часть структуры данных является монадой.Структуры данных с монадами

У меня возникает ощущение, что я должен использовать fmap или что-то в этом роде, но они дают разные ошибки. У меня также есть проблемы с преобразованием случайного вектора в строку, чтобы напечатать его на экране. Я не знаю разницы между Rand g и MonadRandom m, и какой из них я должен использовать. Последние, похоже, работают, но все примеры онлайн, похоже, используют Rand g. Кроме того. Также оценивается общий обзор кода.

* 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)' не является вектором или структурой данных. Почему у вас есть это 'm' там? – melpomene

+0

Если я не получаю ошибки типа при вызове 'randVector' в' newObj' – tsorn

+1

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

ответ

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) :: -- ????????? 

Проблема заключается в том, что Obj m не Rand StdGen a. Поэтому вы не можете использовать evalRandIO.

Однако на самом деле нет смысла размещать m внутри Obj. Это возможно, но не очень удобно. Мы могли бы исправить ваш код, если мы использовали

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

Но это все еще не так просто. Вместо этого, давайте упростим Obj:

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

Теперь давайте перепишем newObj, так что она возвращает m Obj:

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) 

И все нормально. Это также позволяет использовать ваши Obj в функциях, которые не знают, что вы работаете в MonadRandom, например.

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

Относится к последней точке. Возможно ли это только в том случае, если 'm Obj' был связан внутри монадической функции? Если нет, то откуда я знаю, что функция не знает, что она работает в «MonadRandom»? Потому что я не могу удалить «MonadRandom m» из сигнатуры типа «randVector», хотя сама функция ничего не использует из «MonadRandom». – tsorn