【问题标题】:Mutability: directly or via ST Monad可变性:直接或通过 ST Monad
【发布时间】:2014-12-21 16:00:55
【问题描述】:

我正在关注斯坦福算法 MOOC 并尝试使用 Haskell 解决这些问题。许多算法需要大量的数据处理,纯解决方案的运行速度比人们为命令式语言引用的基准要慢得多。所以我觉得我需要使用可变数据结构。

大多数 Haskell 数据结构似乎都有可变的等价物,但有很多关于使用它们的警告。通过 IO Monad 实现这些似乎很容易,但我得到的印象是“更纯粹”的方式是使用 ST Monad,但在后一种情况下,我只看到提到的数组,其中 runSTArray 可用(见下面的代码)。我错过了什么吗?

main = do
    let
        inputData = [1,10,4,3,2]
    print $ elems $ runSTArray $ do
        --newListArray :: (MArray a e m, Ix i) => (i, i) -> [e] -> m (a i e)
        state <- newListArray (1, length inputData) inputData
        qsort state 1 (length inputData)
        return state

qsort :: (STArray s Int Int) -> Int -> Int -> ST s ()
qsort arr min mx =
    if mx - min < 1 then
        return ()

    else do
        p <- readArray arr min
        final_i <- foldM (partitioner p) (min+1) [(min+1)..mx]
        swap min $ final_i - 1
        qsort arr min     (final_i-2)
        qsort arr final_i mx     

    where
        swap i j = do
            arr_i <- readArray arr i
            arr_j <- readArray arr j
            writeArray arr i arr_j
            writeArray arr j arr_i

        partitioner p i idx = do
            arr_idx <- readArray arr idx
            if arr_idx > p then
                return i
            else do
                swap i idx
                return $ i+1

具体来说,以上和以下的有效区别是什么:

main = do
    [snip]
    arr <- newListArray (0, length inputData - 1) inputData :: IO (IOArray Int Int)
    qsort arr 0 (length inputData - 1)
    printArray arr

qsort :: (IOArray Int Int) -> Int -> Int -> IO ()
[As above]

再想一想:这个问题不就是 ST 和 IO Monad 之间的区别吗,外行的答案是 ST 更“安全”?

【问题讨论】:

  • 你想使用什么数据结构?向量? Data.Vector.Unboxed.MutableSTIO 中工作。一张地图? Data.Map 非常快,如果您需要可变值 in 映射,您可以简单地使用 STRef。来自整数值的地图? Data.IntMap 更快。你应该在你的问题中添加一个具体的问题,否则它可能太宽泛了。
  • “大多数 Haskell 数据结构似乎都有可变等价物”。他们有吗?
  • 还值得考虑的是,从 List 跳转到 Vector 通常是不合理的,例如,您可以使用既高性能又纯的序列。另外,请使用 Vector 而不是 Array。
  • @alternative 我会调查的。同时,我现在了解如何将 ST 与 Vectors 一起使用:print $ elems $ runST $ do [...]; frozen &lt;- freeze state; return frozen。我发现的所有数据结构示例都使用runSTArray,这相当欺骗了我
  • @SimonH 我认为 Vector 或多或少也回答了你的问题。如果您查看类型,它不会在 ST 或 IO 中运行,它在 PrimMonad 类型类中运行,该类型类具有 ST 和 IO 的实例。因此,您可以使用相同的代码在两者中测试相同的东西,并且您可能会发现它们的性能相同。

标签: haskell


【解决方案1】:

是的,您缺少模块 Data.STRef。您可以使用newSTRef 创建可变变量,使用writeSTRef 存储变量并使用readSTRef 获取变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-22
    • 1970-01-01
    • 1970-01-01
    • 2017-09-03
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多