使用Data.Vector.Unboxed.Mutable创建1..N的随机排列

时间:2016-05-15 21:01:48

标签: haskell vector

我想创建一个包含数字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_

2 个答案:

答案 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