重复数据构造函数

时间:2016-10-05 09:53:06

标签: haskell

我可以定义二叉树数据结构:

data Tree a = Leaf | Node a (Tree a) (Tree a)

现在我想创建一个树,使每个Node有10个子树。我可以通过写出10 (Tree a)来做到这一点,但有更简洁的方法吗?我认为类型家庭可能在这里有所帮助,但我不确定。

1 个答案:

答案 0 :(得分:2)

您似乎想要一个树,其分支因子是在类型级别确定的,并且可以是任何自然数。 GADTs非常简单:

data Nat = Z | S Nat 

data Vec (n :: Nat) a where 
  Nil :: Vec 'Z a 
  (:>) :: a -> Vec n a -> Vec ('S n) a 
infixr 5 :> 

data Tree k a = Leaf | Node a (Vec k (Tree k a))

Vec是用GADT编码同源长度索引向量的标准方法(例如here)。树中的节点是类型a的元素和长度为k的向量,其中向量的每个元素都是子树。

二元树只是

type BinaryTree = Tree ('S ('S 'Z))

和构建就是

tree = Node 1 (Node 2 (Leaf :> Leaf :> Nil) :> Leaf :> Nil)

推断类型为Num a => Tree ('S ('S 'Z)) a

但如果你真的需要10个节点,写出10个'S仍然太繁琐,所以你可能想要使用类型文字:

import qualified GHC.TypeLits as TL

...

type family N (n :: TL.Nat) :: Nat where  
  N 0 = 'Z 
  N n = 'S (N (n TL.- 1))

type Tree10 = Tree (N 10)

这不仅为您提供了您喜欢的任何分支因子,而且它允许您编写分支因子中具有多态性的函数,甚至更多,GHC免费为您提供以下所有内容:

-- With StandaloneDeriving, DeriveFunctor, DeriveFoldable, DeriveTraversable
deriving instance Functor (Vec k) 
deriving instance Foldable (Vec k) 
deriving instance Traversable (Vec k) 

deriving instance Functor (Tree k)
deriving instance Foldable (Tree k) 
deriving instance Traversable (Tree k)