{-# LANGUAGE GADTs, ExistentialQuantification, ScopedTypeVariables,
             Rank2Types #-}

-- Here's an example from Doaitse Swiestra (Sept 06)
-- which requires use of scoped type variables
-- 
-- It's a cut-down version of a larger program
--
-- It's also one which was sensitive to syntactic order
-- in GHC 6.4; but not in 6.6

module ShouldCompile where

data Exists f = forall a . Exists (f a)

data Ref env a where
  Zero :: Ref (a,env') a
  Suc  :: Ref env' a -> Ref (x,env') a

data Find env final = Find (forall a . Ref env a -> Maybe (Ref final a))

data Equal a b where
  Eq :: Equal a a

sym :: Equal a b -> Equal b a
sym Eq = Eq

match' :: Ref env' a -> Ref env'' a -> Bool
match' _ _ = True

match :: Ref env a -> Ref env b -> Maybe (Equal a b)
match Zero Zero      = Just Eq
match (Suc x)(Suc y) = match x y
match _ _            = Nothing

-- Notice the essential type sig for the argument to Exists
f1 :: forall env.  (Exists (Ref env)) -> Exists (Find  env)
f1 (Exists (ref1 :: Ref env b))
  = Exists ( Find (\ ref2 -> case match ref2 ref1 of
                                Just Eq -> Just Zero
                                _       -> Nothing
                  ):: Find env (b,())
   )


-- same as 'f1' except that 'ref1' and 'ref2' are swapped in the  
-- application of 'match'
f2 :: forall env.  (Exists (Ref env)) -> Exists (Find  env)
f2 (Exists (ref1 :: Ref env b))
   = Exists (Find (\ ref2 -> case match ref1 ref2 of
                                    Just Eq -> Just Zero
                                    _       -> Nothing
                    ) :: Find env (b,())
     )

