Bas van Dijk wrote:
Roberto Zunino wrote:
>>
data Z
data S n
data List a len where
   Nil :: List a Z
   Cons:: a -> List a len -> List a (S len)

>
The other day I was playing with exactly this GADT. See: http://hpaste.org/2707

My aim was to define a function like 'concat' in terms of 'foldr' but
I was unable to do so. Can this be done?

Not with the standard foldr you mimic. I mean, in reality, foldr is (almost) the induction principle for natural numbers! Given a property p that you want to prove for all natural numbers n , the induction principle reads

  induction :: forall p .
        (forall n . p n -> p (S n)) -- induction step
     -> p Z                         -- induction base
     -> (forall n . p n)            -- it holds!

Similarly, the right type of foldr is

  foldr :: forall b a .
     -> (forall n . a -> b n -> b (S n))
     -> b Z
     -> (forall n . List a n -> b n)

or without the superfluous foralls

  foldr :: (forall n . a -> b n -> b (S n)) -> b Z -> List a n -> b n

The implementation is exactly the same

  foldr _ z Nil         = z
  foldr f z (Cons x xs) = f x (foldr f z xs)

Put differently, you just add the length parameter to b.


For concat, we have to set

  b n = List a (Sum n m)

Given only List a (Sum n m), the Haskell type checker can't figure out that it is of the form b n for some type constructor b . The solution is to introduce a newtype to guide it

  newtype PlusList a m n = In { out :: List a (Sum n m) }

so that we now have b = (PlusList a m) and we can write

  concat :: forall a m n . List a n -> List a m -> List a (Sum n m)
  concat xs ys = out (foldr f z xs)
    where
    f :: a -> PlusList a m n -> PlusList a m (S n)
    f x b = In (cons x (out b))
    z :: PlusList a m Z
    z = In ys

I didn't test this code, but it should work ;)

Also I was unable to define the function 'fromList :: [a] -> ListN a
n'. This makes sense of course because statically the size of the list
is unknown. However maybe existential quantification can help but I'm
not sure how.

The return type of  fromList  can't be

  fromList :: [a] -> List a n

since that's syntactic sugar for

  fromList :: forall n . [a] -> List a n

i.e. given a list, fromList returns one that has all possible lengths n. Rather, the type should be

  fromList :: [a] -> (exists n . List a n)

i.e. there exists a length which the returned list has. (Exercise: why is (exists n . [a] -> List a n) wrong?)

The data type ListFinite from my other message on this thread does the existential quantification you want. With

  nil  :: ListFinite a
  nil  = IsFinite (Nil)

  cons :: a -> ListFinite a -> ListFinite a
  cons x (IsFinite xs) = IsFinite (Cons x xs)

we can write

  fromList :: [a] -> ListFinite a
  fromList []     = nil
  fromList (x:xs) = cons x (fromList xs)


Regards,
apfelmus

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to