As an introduction, see this question and my answer. I note at the end that it seems that you could remove the need for extraneous type specification with a functional dependency. Here is the code as it stands:
{-# LANGUAGE GADTs, MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies #-}
data Nil
data TList a b where
TEmpty :: TList Nil Nil
(:.) :: c -> TList d e -> TList c (TList d e)
infixr 4 :.
class TApplies f h t r where
tApply :: f -> TList h t -> r
instance TApplies a Nil Nil a where
tApply a _ = a
instance TApplies f h t r => TApplies (a -> f) a (TList h t) r where
tApply f (e :. l) = tApply (f e) l]
Now, the intuitive thing for me to do seems to be to add the fundep f h t -> r
to the
TApplies
typeclass. However, when I do this, GHC complains about the recursive instance of TApplies
as follows:
Illegal instance declaration for
‘TApplies (a -> f) a (TList h t) r’
The coverage condition fails in class ‘TApplies’
for functional dependency: ‘f h t -> r’
Reason: lhs types ‘a -> f’, ‘a’, ‘TList h t’
do not jointly determine rhs type ‘r’
The last two lines seem wrong to me, although I expect I simply misunderstand something. My reasoning is as follows:
- If we have
a -> f
anda
, then we havef
. - If we have
TList h t
then we haveh
andt
. - Since we have
TApplies f h t r
, we have the fundepf h t -> r
. - Therefore, because we have
f
,h
andt
, we haver
.
This implies to me that the functional dependency is satified. Can someone point out the flaw in my logic, and also perhaps suggest a more apt choice of functional dependency? (Note that something like f r -> h
is permitted by GHC but does not seem to provide much leeway in type indication.)