我想创建一个包含数字1到N的随机排列的列表。据我所知,可以在runST中使用VUM.swap
,但由于我需要随机数,我想我可以在IO monad中同时执行这两项操作。
以下代码产生:
预期类型:IO(VU.Vector Int),实际类型:IO(VU.Vector (VU.Vector a0))
表示return语句。
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VUM
import System.Random
randVector :: Int -> IO (VU.Vector Int)
randVector n = do
vector <- VU.unsafeThaw $ VU.enumFromN 1 n
VU.forM_ (VU.fromList [2..VUM.length vector]) $ \i -> do
j <- randomRIO(0, i) :: IO Int
VUM.swap vector i j
return $ VU.unsafeFreeze vector
我不太清楚为什么返回向量是嵌套的。我是否必须使用VU.fold1M_
?
答案 0 :(得分:3)
unsafeFreeze vector
已经返回IO (VU.Vector Int)
。只需将最后一行更改为VU.unsafeFreeze vector
。
另一方面,您应该迭代到VUM.length vector - 1
,因为[x .. y]
和randomRIO
都使用包含范围。此外,您可以在此处使用普通forM_
进行迭代,因为您只关心副作用。
import Control.Monad
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VUM
import System.Random
randVector :: Int -> IO (VU.Vector Int)
randVector n = do
vector <- VU.unsafeThaw $ VU.enumFromN 1 n
forM_ [2..VUM.length vector - 1] $ \i -> do
j <- randomRIO(0, i) :: IO Int
VUM.swap vector i j
VU.unsafeFreeze vector
我查看了生成的代码,似乎GHC 7.10.3 forM_
编译为有效循环,而VU.forM_
保留中间列表并且肯定明显更慢(这是我的预期结果对于forM_
,但我不确定VU.forM_
)。
答案 1 :(得分:1)
我会尝试(注意最后更新):
import Control.Monad
randVector :: Int -> IO (VU.Vector Int)
randVector n = do
vector <- VU.unsafeThaw $ VU.enumFromN 1 n
forM_ [2..VUM.length vector] $ \i -> do
j <- randomRIO(0, i) :: IO Int
VUM.swap vector i j
return $ VU.unsafeFreeze vector
编辑:正如@AndrásKovács指出的那样,你不希望最后的return
所以最后一行应该是:
VU.unsafeFreeze vector