Haskell中的一些常见performance advice是使快速数据结构“严格”,以便在创建时对结构(但不一定是其内容)进行全面评估。当我们插入一个值并且结构在缓存中时,这让我们可以做更多工作,而不是在我们查看值之前将其关闭。
使用普通数据类型,如Data.IntMap中的二进制trie,可以通过严格限制数据结构中的相关字段来实现:
data IntMap a = Bin {- ... -} !(IntMap a) !(IntMap a)
| {- ... -}
(摘自Data.IntMap.Base来源。)
如果我想将子项存储在向量中而不是直接存储为Bin
的字段,我该如何实现相同的行为?
data IntMap a = Bin {- ... -} (Vector (IntMap a))
| {- ... -}
答案 0 :(得分:2)
首先,我将回答问题的一个简单变体:
如果您的数据类型不可用,例如你想要一个Int
s的严格向量,
使用Data.Vector.Unboxed
。
作为免费奖励,实现允许您拥有数组",(Vector a, Vector b)
的结构,甚至接口
不容易出错"结构数组",Vector (a, b)
。
请参阅Wikipedia on AOS and SOA。
然而,在OPs问题中,我们希望将IntMap a
加入Vector
,并且
IntMap
不可用(或可存储或原始)。
各种选项归结为同一个想法:你必须自己seq
重视。
你是否愿意
Data.Primitive.Array
或者在Data.Vector.Strict
之上实施自己的Data.Vector
(注意:basicClear
可以是no-op as
它适用于未装箱的矢量,或者您可以使用unsafeCoerce ()
作为虚拟值),
你会seq
价值。这是怎么回事
Data.Map.Strict
已在顶部实施
与Data.Map.Lazy
相同的惰性结构。
例如
map
Data.Map.Strict
实现为:
map :: (a -> b) -> Map k a -> Map k b
map f = go
where
go Tip = Tip
go (Bin sx kx x l r) = let !x' = f x in Bin sx kx x' (go l) (go r)
将其与Data.Map.Lazy.map
:
map :: (a -> b) -> Map k a -> Map k b
map f = go where
go Tip = Tip
go (Bin sx kx x l r) = Bin sx kx (f x) (go l) (go r)