There is a relevant question concerning Functional Dependencies used with GADTs. It turns out that the problem is not using those two together, since similar problems arise without the use of GADTs. The question is not definitively answered, and there is a debate in the comments.
The problem
I am trying to make a heterogeneous list type which contains its length in the type (sort of like a tuple), and I am having a compiling error when I define the function "first" that returns the first element of the list (code below). I do not understand what it could be, since the tests I have done have the expected outcomes.
I am a mathematician, and a beginner to programming and Haskell.
The code
I am using the following language extensions:
{-# LANGUAGE GADTs, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}
First, I defined natural numbers in the type level:
data Zero = Zero
newtype S n = S n
class TInt i
instance TInt Zero
instance (TInt i) => TInt (S i)
Then, I defined a heterogeneous list type, along with a type class that provides the type of the first element:
data HList a as where
EmptyList :: HList a as
HLCons :: a -> HList b bs -> HList a (HList b bs)
class First list a | list -> a
instance First (HList a as) a
And finally, I defined the Tuple type:
data Tuple list length where
EmptyTuple :: Tuple a Zero
TCons :: (TInt length) => a -> Tuple list length -> Tuple (HList a list) (S length)
I wanted to have the function:
first :: (First list a) => Tuple list length -> a
first EmptyTuple = error "first: empty Tuple"
first (TCons x _) = x
but it does not compile, with a long error that appears to be that it cannot match the type of x with a.
Could not deduce: a1 ~ a
from the context: (list ~ HList a1 list1, length ~ S length1,
TInt length1)
bound by a pattern with constructor:
TCons :: forall length a list.
TInt length =>
a -> Tuple list length -> Tuple (HList a list) (S length),
in an equation for ‘first’
[...]
Relevant bindings include
x :: a1 (bound at problem.hs:26:14)
first :: Tuple list length -> a (bound at problem.hs:25:1)
The testing
I have tested the type class First by defining:
testFirst :: (First list a) => Tuple list length -> a
testFirst = undefined
and checking the type of (testFirst x). For example:
ghci> x = TCons 'a' (TCons 5 (TCons "lalala" EmptyTuple))
ghci> :t (testFirst x)
(testFirst x) :: Char
Also this works as you would expect:
testMatching :: (Tuple (HList a as) n) -> a
testMatching (TCons x _) = x
"first" is basically these two combined.
The question
Am I attempting to do something the language does not support (maybe?), or have I stumbled on a bug (unlikely), or something else (most likely)?