如何使用未装箱可变向量

day*_*ion 5 haskell

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
Run Code Online (Sandbox Code Playgroud)

我正在实施 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
Run Code Online (Sandbox Code Playgroud)

Mat*_*hid 8

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

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

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

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

  • 这很有帮助。他们应该将其放在文档中,用外行术语并举例说明 (2认同)
  • @daydaynation你正在编写一个快速排序函数。对其输入进行排序,并生成其排序版本。即使你错误地实现了它,它总是会根据你编写的代码做*某事*,*某事*,*相同*的事情。引入不可预测的变化的唯一方法是通过“IO”代码使用某些 I/O 方式,例如随机,或根据某些不可预测的外部源做出某些决定。但无法逃脱“IO”。可以从“ST”中逃脱,因为它没有不可预测性,没有随机性,没有 I/O。所有这些都存在于“IO”单子中,而不是“ST”单子中。 (2认同)