Jonathan S.目前有一个pull request将Data.IntMap
的实施替换为this README中根据Edward blog post提出的问题解释的一个{/ 1}}。
Jonathan S.开发的基本概念是IntMap
是一个看起来像这样的二叉树(为了保持一致性,我对他的开发做了一些细微的改动):
data IntMap0 a = Empty | NonEmpty (IntMapNE0 a)
data IntMapNE0 a =
Tip !Int a
| Bin { lo :: !Int
, hi :: !Int
, left :: !(IntMapNE0 a)
, right :: !(IntMapNE0 a) }
在此表示中,每个节点都有一个字段,指示IntMapNE0
中包含的最小和最大密钥。使用一点点摆弄可以将其用作PATRICIA trie。 Jonathan指出,这种结构的范围信息几乎是它所需要的两倍。左侧或右侧脊柱将产生所有相同的lo
或hi
边界。所以他只是包括了祖先没有确定的界限来削减它们:
data IntMap1 a = Empty | NonEmpty { topLo :: !Int, child :: !(IntMapNE1 a) }
data IntMapNE1 a =
Tip a
| IntMapNE1 { bound :: !Int
, left :: !(IntMapNE1 a)
, right :: !(IntMapNE1 a)
现在每个节点都有左边界或右边界,但不是两者都有。正确的孩子只有左边界,而左边的孩子只有右边界。
Jonathan做了一个进一步的改变,将值从叶子移动到内部节点,这将它们准确地放置在它们的确定位置。他还使用幻像类型来帮助跟踪左右。最后的类型(现在,无论如何)是
data L
data R
newtype IntMap a = IntMap (IntMap_ L a) deriving (Eq)
data IntMap_ t a = NonEmpty !Int a !(Node t a) | Empty deriving (Eq)
data Node t a = Bin !Int a !(Node L a) !(Node R a) | Tip deriving (Eq, Show)
这项新实施的某些方面非常有吸引力。最重要的是,许多最常用的操作都要快得多。不太重要,但很好的是,所涉及的小小问题更容易理解。
然而,有一个严重的痛点:将缺失的范围信息传递到树中。这对于查找,插入等来说并不是那么糟糕,但在联合和交集代码中却非常严重。是否有一些抽象可以自动完成?
一些非常含糊的想法:
幻影类型可以与自定义类一起使用,直接将治疗与手性联系起来吗?
“缺失的部分”性质有点像一些拉链情况。可能有办法使用该领域的想法吗?
我开始考虑使用某种类型的中间类型来提供结构的对称“视图”,但我有点卡住了。我可以很容易地在基本结构和花哨的结构之间来回转换,但转换是递归的。我需要一种只能部分转换的方法,但是我不太了解有关完美构建的类型以完成它。
答案 0 :(得分:2)
是否有一些抽象可以自动完成?
您应该能够定义一组模式同义词,为您提供。我将从你的代码的倒数第二个变种开始,即:
data IntMap1 a = Empty | NonEmpty { topLo :: !Int, child :: !(IntMapNE1 a) }
data IntMapNE1 a =
Tip a
| IntMapNE1 { bound :: !Int
, left :: !(IntMapNE1 a)
, right :: !(IntMapNE1 a)
我们使用Either
中父项的边界来表示这样的值(表示它是低限还是高限)。
viewLoHi (Left lo, IntMapNE1 hi left right)
= Just (lo, hi, (Left lo, left), (Right hi, right)
viewLoHi (Right hi, IntMapNE1 lo left right)
= Just (lo, hi, (Left lo, left), (Right hi, right)
viewLoHi _
= Nothing
pattern Bin' lo hi left right <- (viewLoHi -> Just (lo, hi, left, right))
顶级数据类型不同,因此需要自己的模式同义词
viewLoHi' (NonEmpty lo child) = viewLoHi (Left lo, child)
viewLoHi' Empty = Nothing
pattern NonEmpty' lo hi left right <- (viewLoHi' -> Just (lo, hi, left, right)
在遍历树时仅使用NonEmpty'
和Bin'
,现在应完全隐藏簿记。 (代码未经过测试,因此这里会出现拼写错误)