有没有办法减少范围跟踪的痛苦?

时间:2016-09-15 21:06:07

标签: haskell data-structures patricia-trie

Jonathan S.目前有一个pull requestData.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指出,这种结构的范围信息几乎是它所需要的两倍。左侧或右侧脊柱将产生所有相同的lohi边界。所以他只是包括了祖先没有确定的界限来削减它们:

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)

这项新实施的某些方面非常有吸引力。最重要的是,许多最常用的操作都要快得多。不太重要,但很好的是,所涉及的小小问题更容易理解。

然而,有一个严重的痛点:将缺失的范围信息传递到树中。这对于查找,插入等来说并不是那么糟糕,但在联合和交集代码中却非常严重。是否有一些抽象可以自动完成?

一些非常含糊的想法:

  1. 幻影类型可以与自定义类一起使用,直接将治疗与手性联系起来吗?

  2. “缺失的部分”性质有点像一些拉链情况。可能有办法使用该领域的想法吗?

  3. 我开始考虑使用某种类型的中间类型来提供结构的对称“视图”,但我有点卡住了。我可以很容易地在基本结构和花哨的结构之间来回转换,但转换是递归的。我需要一种只能部分转换的方法,但是我不太了解有关完美构建的类型以完成它。

1 个答案:

答案 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',现在应完全隐藏簿记。 (代码未经过测试,因此这里会出现拼写错误)