如果我正在计算字符串中字符的出现次数,我可以使用命令式语言中的数组轻松实现这一点,例如:
char values[256]; char c;
while (c = readChar()) {
values[c] += 1;
}
我可以看到如何在Haskell中使用像Data.Vector.Mutable
这样的东西来做这件事,它提供了快速实现的int-indexed可变数组。
但是我怎样才能使用Haskell轻松实现这一点而没有额外的包和/或扩展?换句话说,如何实现具有索引和可变性的快速O(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
包,它更加优化(流融合,......)并且更易于使用。