GADT的类型约束不足,无法处理不可预测的数据

时间:2018-12-23 15:23:23

标签: haskell io gadt

我正在尝试利用GADT来限制类型,但是在编译期间无法处理某些依赖项,例如用户输入。让我们考虑以下AVL树定义:

data Zero
data S a

data AVL depth where
  Nil :: AVL Zero
  LNode :: AVL n -> Int -> AVL (S n) -> AVL (S (S n))
  RNode :: AVL (S n) -> Int -> AVL n -> AVL (S (S n))
  MNode :: AVL n -> Int -> AVL n -> AVL (S n)

GADT的魔力确保每棵AVL树都得到很好的平衡。我可以定义一些基本功能,例如

singleton :: a -> AVL (S Zero) x
singleton a = MNode Nil a Nil

insert :: a -> AVL n a -> AVL (S n) a
insert = ...

现在,我想编写一个程序,该程序将读取n个数字,将它们插入AVL树并按顺序返回(假设已定义这些函数):

main = IO ()
main = do
  (n :: Int) <- readInt  -- some IO defined somewhere
  (inp :: [Int]) <- readInts
  let avl = foldl (\tree x -> insert x tree) Nil inp
  print $ toList avl

显然我得到了错误:

    • Couldn't match type ‘S Zero’ with ‘Zero’
      Expected type: AVL Zero
        Actual type: AVL (S Zero)

因为树的类型(深度)将随着每个insert而变化。我了解这里发生的情况,但是在处理“在线”输入时,我看不到任何使用此AVL的合理方法-这完全不知道我要插入多少个元素。

有什么解决方案可以让我为这种情况抽象出树的深度吗?即使AVL太复杂了,这个问题也适用于编译时大小的向量和矩阵。目前,我只能解决硬编码的任务,这使我的程序完全不灵活。

1 个答案:

答案 0 :(得分:8)

您可以使用其他GADT隐藏树的深度。 (这被称为存在类型。)

data SomeAVL a where
  SomeAVL :: AVL n a -> SomeAVL a

使用包装器可对SomeAVL进行操作:

insert' :: a -> SomeAVL a -> SomeAVL a
insert' a (SomeAVL t) = SomeAVL (insert a t)