红黑树的Haskell算者

时间:2014-05-15 09:22:39

标签: haskell functor red-black-tree

所以我正在学习Haskell,我有一个红黑树,红色和黑色节点的类型不同,实现如下:

data Rbtree a1 b1 = EmptyTree | Node a1 (Rbtree b1 a1) (Rbtree b1 a1) deriving (Show, Read, Eq)

现在我需要为它定义一个仿函数实例。因为Rbtree是一个带有两个参数的类型构造函数,所以我必须为Rbtree c创建一个实例。在此之后我被困住了。我的代码现在是这样的:

instance Functor (Rbtree c) where
fmap f EmptyTree = EmptyTree
fmap f (Node x left right) = Node x (fmap f left) (fmap f right)

正如你猜测的那样,不能编译。 (compilation errors)。我理解,fmap必须为(a -> b) -> (Rbtree c) a -> (Rbtree c) b并且要更深入地了解Node部分,它必须是(a -> b) -> (Node c (Rbtree a c) (Rbree a c)) -> (Node c (Rbtree b c) (Rbree b c))。我不明白的是如何展开leftright所以我只能将f应用于其中的一部分。我想我在这里错过了一些东西。

3 个答案:

答案 0 :(得分:8)

您可以像这样Rbtree Bifunctor import Data.Bifunctor data Rbtree a1 b1 = EmptyTree | Node a1 (Rbtree b1 a1) (Rbtree b1 a1) instance Bifunctor Rbtree where bimap _ _ EmptyTree = EmptyTree bimap f g (Node x l r) = Node (f x) (bimap g f l) (bimap g f r) (见bifunctors package):

first

通过此实例,您现在可以使用secondsecond函数来映射红色或黑色节点(fmapFunctor)。实际上你可以像这样定义instance Functor (Rbtree c) where fmap = second 个实例:

>>> let t = Node 1 (Node "hello" EmptyTree EmptyTree) EmptyTree
>>> bimap show length t
Node "1" (Node 5 EmptyTree EmptyTree) EmptyTree
>>> fmap length t
Node 1 (Node 5 EmptyTree EmptyTree) EmptyTree
>>> first show t
Node "1" (Node "hello" EmptyTree EmptyTree) EmptyTree

实施例

{{1}}

答案 1 :(得分:3)

您可以使用Red-Black tree invariants和某些类型hackery(GADTsexistential quantificationtype arithmetic)强制执行所有data kinds。属性是:

  1. 节点为红色或黑色。
  2. 根是黑色的。
  3. 所有叶子(NIL)都是黑色。
  4. 每个红色节点必须有两个黑色子节点。
  5. 从给定节点到其任何后代的每条路径 leaves包含相同数量的黑色节点。
  6. 以下是示例代码:

    {-# LANGUAGE GADTs, StandaloneDeriving, ExistentialQuantification,
                 KindSignatures, DataKinds #-}
    
    data Nat = Zero | Succ Nat
    data Color = Red | Black
    
    data Node :: Color -> Nat -> * -> * where
        Nil :: Node Black Zero a
        RedNode :: a -> Node Black n a -> Node Black n a -> Node Red n a
        BlackNode :: a -> Node c1 n a -> Node c2 n a -> Node Black (Succ n) a
    
    data RBTree a = forall n. RBTree (Node Black n a)
    
    deriving instance (Show a) => Show (Node c n a)
    deriving instance (Show a) => Show (RBTree a)
    
    instance Functor (Node c n) where
        fmap f Nil = Nil
        fmap f (RedNode   x l r) = RedNode   (f x) (fmap f l) (fmap f r)
        fmap f (BlackNode x l r) = BlackNode (f x) (fmap f l) (fmap f r)
    
    instance Functor RBTree where
        fmap f (RBTree t) = RBTree (fmap f t)
    

    你可以像这样使用它:

    tree = RBTree $ BlackNode 3 (RedNode 4 Nil Nil) (RedNode 5 Nil Nil)
    main = print $ fmap (*5) tree
    

    结果:

    RBTree (BlackNode 15 (RedNode 20 Nil Nil) (RedNode 25 Nil Nil))
    

    但这不会编译:

    tree = RBTree $ BlackNode 3 (RedNode 4 Nil Nil) (BlackNode 5 Nil Nil)
    

    您将收到 nice 错误消息:

    Couldn't match type `Succ Zero' with `Zero'
    Expected type: Node Black Zero a0
      Actual type: Node Black (Succ Zero) a0
    In the return type of a call of `BlackNode'
    In the third argument of `BlackNode', namely
      `(BlackNode 5 Nil Nil)'
    In the second argument of `($)', namely
      `BlackNode 3 (RedNode 4 Nil Nil) (BlackNode 5 Nil Nil)'
    

答案 2 :(得分:2)

instance Functor (Rbtree c) where
  fmap = fmap_even where
     fmap_even _ EmptyTree = EmptyTree
     fmap_even f (Node x left right) = Node x (fmap_odd f left) (fmap_odd f right)
     fmap_odd  _ EmptyTree = EmptyTree
     fmap_odd  f (Node x left right) = Node (f x) (fmap_even f left) (fmap_even f right)

你对RB树的定义对我来说没有多大意义,但是如果我遗漏了某些东西,这里有一个与它兼容的Functor实例。