The length calculation looked complicated. So I reformulated it as a comparison
using HasIndex. But ghc-6.8.2 was not inferring the recursive constraint on
proj, so I split proj into proj_unsafe without the constraint and proj with the
constraint checked only once. I also renamed ZT to Nil to be more consistent.
-- works in ghc 6.8.2
{-# LANGUAGE GADTs, TypeFamilies, EmptyDataDecls, TypeOperators #-}
data FZ
data FS a
data Fin fn where
FZ :: Fin FZ
FS :: Fin fn -> Fin (FS fn)
f0 = FZ
f1 = FS f0
f2 = FS f1
-- ... etc.
data Nil
data t ::: ts
infixr 4 :::
data Tuple ts where
Nil :: Tuple Nil
(:::) :: t -> !(Tuple ts) -> Tuple (t ::: ts)
data HTrue
type family Lookup ts fn :: *
type instance Lookup (t ::: ts) FZ = t
type instance Lookup (t ::: ts) (FS fn) = Lookup ts fn
type family HasIndex ts fn :: *
type instance HasIndex (t ::: ts) FZ = HTrue
type instance HasIndex (t ::: ts) (FS fn) = HasIndex ts fn
{-# INLINE proj #-}
proj :: (HasIndex tsT fnT ~ HTrue) => Fin fnT -> Tuple tsT -> Lookup tsT fnT
proj = proj_unsafe where
proj_unsafe :: Fin fnT -> Tuple tsT -> Lookup tsT fnT
proj_unsafe (FS fn) (_v ::: vs) = proj_unsafe fn vs
proj_unsafe FZ (v ::: _vs) = v
proj_unsafe _ Nil = error "Cannot proj Nil in proj_unsafe"
fst' :: (HasIndex ts FZ ~ HTrue) => Tuple ts -> Lookup ts FZ
fst' = proj f0
snd' :: (HasIndex ts (FS FZ) ~ HTrue) => Tuple ts -> Lookup ts (FS FZ)
snd' = proj f1
pair :: Tuple (Char ::: (() ::: Nil))
pair = 'a' ::: () ::: Nil
q1 :: Char
q1 = fst' pair
q2 :: ()
q2 = snd' pair
{- This won't compile
q2 :: ()
q2 = snd' ('a' ::: Nil)
-}
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe