Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weaken GADTs type constraints to deal with unpredictable data

Tags:

io

haskell

gadt

I am trying to make use of GADTs to have well constrained types, but some dependencies are impossible to handle during compilation time – for example user input. Let's consider following AVL tree definition:

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)

Magic of GADTs ensures that every AVL tree is well balanced. I can define some basic functions like

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

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

Now I would like to write program that will read n numbers, insert them into AVL tree and return in order (assuming that these functions are defined):

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

And obviously I get error:

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

because type (depth) of the tree is going to change along with every insert. I understand what is happening here, but I don't see any reasonable way to use this AVL while handling input "online" – that is without any knowledge of how many elements I am going to insert.

Is there any solution that would allow me to abstract out tree's depth for this case? Even if AVL is too complicated example, this problem applies also to compile-time-sized vectors and matrices. For now I can solve only hardcoded tasks, which makes my programs completely inflexible.

like image 934
radrow Avatar asked Dec 23 '18 15:12

radrow


1 Answers

You can use another GADT to hide the depth of the tree. (This is called an existential type.)

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

With wrappers to operate on SomeAVLs:

insert' :: a -> SomeAVL a -> SomeAVL a
insert' a (SomeAVL t) = SomeAVL (insert a t)
like image 138
Li-yao Xia Avatar answered Oct 20 '22 19:10

Li-yao Xia