如何使用未装箱可变向量

import           Control.Monad.ST
import           Data.STRef

import qualified Data.Vector.Unboxed         as V
import qualified Data.Vector.Unboxed.Mutable as MV

-- what the heck is that s?
new0 :: (MV.Unbox a, Num a) => ST s (MV.STVector s a)
new0 = do
  v <- MV.new 10
  MV.write v 1 10
  MV.write v 2 10
  return v

new1 :: (MV.Unbox a) => IO (MV.IOVector a)
new1 = MV.new 10

new2 :: (MV.Unbox a, Num a) => IO (MV.STVector RealWorld a)
new2 = do
  v <- MV.new 10
  MV.write v 1 10
  return v

我正在实施 QuickSort 算法,我选择 Data.Vector.Unboxed.Mutable

我对两个问题完全迷失了:

  • 如何选择合适的MonadIOST
  • 如何从ST. 谁能告诉我如何打印new0

解决方案:

我从这个示例代码中得到了一些灵​​感

为了更好地理解STmonad,请查看原始论文:Lazy Functional State Threads

这是一个代码片段,展示了如何使用可变向量进行快速排序:

import           Control.Monad.Primitive
import           Control.Monad.ST            (runST)
import           Prelude                     hiding (read)

import           Data.List                   (partition)
import qualified Data.Vector.Unboxed         as V
import qualified Data.Vector.Unboxed.Mutable as M

partitionV :: (PrimMonad m, Ord a, V.Unbox a) 
           => M.MVector (PrimState m) a -> Int -> Int -> m Int
partitionV v p r = do
  let i = p
  x <- M.unsafeRead v r
  go i p x
  where
    go i j x | j < r = do
               jv <- M.unsafeRead v j
               if jv < x
                 then M.unsafeSwap v i j >> go (i+1) (j+1) x
                 else go i (j+1) x
    go i _ _ = do
      M.unsafeSwap v i r
      return i

quickSortV :: (PrimMonad m, Ord a, V.Unbox a) 
           => M.MVector (PrimState m) a -> m ()
quickSortV v | M.length v < 2 = return ()
quickSortV v = do
  i <- partitionV v 0 (M.length v - 1)
  quickSortV (M.unsafeSlice 0 i v)
  quickSortV (M.unsafeSlice (i + 1) (M.length v - 1 - i) v)
    -- note the difference between for loop and recursive call

test l = runST $ do
  mv <- V.thaw l
  quickSortV mv
  V.freeze mv

quickSort :: (Ord a) => [a] -> [a]
quickSort []       = []
quickSort (x : xs) =
    let (lt, gt) = partition (<= x) xs
    in  quickSort lt ++ [x] ++ quickSort gt

回答

ST单子是当你要采取一些不可改变的数据,使其暂时可变的,用它做什么,并使其再次不可改变。特别是,没有办法STmonad返回可变结果(按设计)。

特别是,STVector是可变的,所以它永远不会离开STmonad。所以没有办法“打印出来” new0。您必须将其转换为不可变的内容才能将其从STmonad 中返回。

如果你想改变某些东西,打印出来,再改变一点,打印出来等等,你可能想要 IO monad。该ST单子是做什么暂时可变的,最终产生一个普通的immeduate结果。

关于s类型变量:这是一个小技巧,它强制执行可变数据不能离开的属性ST。该runST函数需要一个适用于每个可能选择的操作s。这意味着不可能返回任何包含s. 由于所有可变内容都包含s在其类型签名中,因此这加强了我们的保证。

  • This is helpful. They should put it in the doc, in layman's term and with an example
  • @daydaynatation you are writing a quicksort function. is sorts its input, and produces its sorted version. even if you've implemented it incorrectly, it will always do *something*, *some thing*, the *same* thing according to the code you wrote. the only way to introduce unpredictable change is to use some I/O means by an `IO` code, like random, or making some decision depending on some unpredictable external source. but there's no escape from `IO`. there is escape from `ST` because there's no unpredictability in it, no randomness, no I/O. all *that* lives in `IO` monad, not `ST` monad.

以上是如何使用未装箱可变向量的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>