Monad的数据结构

佐恩
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

我在使用monad创建数据结构时遇到了一些麻烦。特别是,数据结构包含一个随机向量和一些其他非随机字段。evalRandIO当整个类型是monad时,使用工作原理,而当数据结构的仅一部分是monad时,则不能工作。

我感觉应该使用fmap或类似的东西,但是它们会给出不同的错误。为了将随机矢量打印到屏幕上,我也遇到了麻烦。我不确定之间的差异Rand gMonadRandom 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 }
泽塔
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不知道您在中操作的in函数MonadRandom,例如

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章