如何在Haskell中实现具有O(1)索引和可变性的集合?

时间:2014-11-27 11:27:49

标签: haskell asymptotic-complexity

如果我正在计算字符串中字符的出现次数,我可以使用命令式语言中的数组轻松实现这一点,例如:

char values[256]; char c;

while (c = readChar()) {
  values[c] += 1;
}

我可以看到如何在Haskell中使用像Data.Vector.Mutable这样的东西来做这件事,它提供了快速实现的int-indexed可变数组。

但是我怎样才能使用Haskell轻松实现这一点而没有额外的包和/或扩展?换句话说,如何实现具有索引和可变性的快速O(1)集合?

1 个答案:

答案 0 :(得分:8)

vector的实现使用称为primops的内部GHC函数。您可以在包含GHC的硬件包ghc-prim中找到它们。它提供了以下数组函数:

newArray# :: Int# -> a -> State# s -> (#State# s, MutableArray# s a#) 
readArray# :: MutableArray# s a -> Int# -> State# s -> (#State# s, a#)
writeArray# :: MutableArray# s a -> Int# -> a -> State# s -> State# s 

这些功能由GHC本身实现,但它们实际上是低级别的。 primitive包提供了这些函数的更好的包装器。对于数组,这些是:

newArray :: PrimMonad m => Int -> a -> m (MutableArray (PrimState m) a) 
readArray :: PrimMonad m => MutableArray (PrimState m) a -> Int -> m a 
writeArray :: PrimMonad m => MutableArray (PrimState m) a -> Int -> a -> m () 

这是一个直接使用这些函数的简单示例(IO是PrimMonad):

import Data.Primitive.Array
import Control.Monad

main :: IO ()
main = do
  arr <- newArray 3 (0 :: Int)
  writeArray arr 0 1
  writeArray arr 1 3
  writeArray arr 2 7
  forM_ [0..2] $ \i -> putStr (show i ++ ":") >> readArray arr i >>= print

当然,在实践中,您只需使用vector包,它更加优化(流融合,......)并且更易于使用。