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