冈崎使用(基本上)
data Color = R | B
data RB a = L | T {-# UNPACK #-}!Color !(RB a) !a !(RB a)
我知道在C中,颜色通常以更加繁琐的方式处理以节省空间,做一些像指针的低位表示颜色(我想通常指针到 a节点对其颜色进行编码,但也可以通过使节点中的左或右指针表示其颜色来模仿Okasaki的结构。
显然,在Haskell中,这种小小的变化是不可能的。那么,如何在Haskell中最有效地表示节点?
data RB' a = L | B !(RB a) !a !(RB a) | R !(RB a) !a !(RB a)
似乎可能具有合理的内存效率,但它似乎也可能使模式匹配相当冗长。
答案 0 :(得分:2)
只能解压缩单个构造函数数据类型,并且无法为多态构造函数提供“泛型解包”。下面的树的单一类型构造实际上将使用指针标记进行存储。它有3个构造函数,其中一个是空的,不包含任何解引用。顺便说一句,GHC似乎有机会进行优化,但我不认为这样做。理论上data Foo = A | B | C | ... Z
可以表示为26个不同的保留指针值。然而,我离题了。
data RB' a = L | B !(RB a) !a !(RB a) | R !(RB a) !a !(RB a)
上述类型将表示为标记指针,模式匹配将非常有效。我想当你提到记忆时,这就是你所指的。如果您知道a
的值,则可以使用关联的数据类型(数据系列)来编写更有效的构造函数。关于这方面的一个很好的资源是Don Stewart的文章Self-optimizing data structures: using types to make lists faster。
数据系列允许您表达类似于此的内容:
class AdaptRedBlackTree a where
data RBTree a
empty :: a
insert :: a -> Tree a -> Tree a
...
instance RedBlackTree Int where
data RBTree Int = RBEmptyInt
| LInt (RBTree Int)
{-# UNPACK #-} Int
(RBTree Int)
| RInt (RBTree Int)
{-# UNPACK #-} Int
(RBTree Int)
不幸的是,进一步拆包会很困难,但至少可以避免对Int
值进行解除引用。