我试图在runST
语句中使用随机生成器并在使用后返回生成器,因此可以在其他地方使用它。
如果我只返回一个向量,则代码会编译,但是当将生成器添加到return语句时,编译将失败。如果我正确理解了错误消息,它说传递给monadic fold的函数不会修改同一状态下的向量,但是我不能弄清楚为什么如果我从返回中省略随机生成器它会编译言。
编译:
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
但这不是:
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')
带有冻结向量和随机生成器的return语句会产生以下错误:
无法将预期类型
ST s (VU.Vector Int, g)
与实际匹配 输入(m0 (VU.Vector Int), g)
答案 0 :(得分:2)
VU.unsafeFreeze vector
在某些monad中返回一个向量(在本例中为ST s
)。请记住,每个动作都必须位于do
表达式中的同一个monad中。由于(VU.unsafeFreeze vector, g')
不属于ST s <something>
类型,因此不适用于runST
。
相反,绑定冻结的向量并使用return
返回类型为ST s (VU.Vector Int, g)
的单对:
g' <- ...
v' <- VU.unsafeFreeze vector
return (v', g')
答案 1 :(得分:2)
查看unsafeFreeze
的类型。
unsafeFreeze :: (Unbox a, PrimMonad m) => MVector (PrimState m) a -> m (Vector a)
这是一个返回m (Vector a)
的monadic计算。因此,表达式(VU.unsafeFreeze vector, g')
的类型为(m (Vector Int), g)
。类型检查器告诉您它无法将此类型与您声明为do
的{{1}}块的类型统一起来。
为了使这些类型统一起来,我们需要将ST s (Vector Int, g)
从元组内部分发到外部;然后类型检查器将推断m
。您需要从其monadic计算中提取m ~ ST s
,然后使用生成器将其打包。
Vector