We can write single, comprehensive instances for parameters of kind *
:
class MyClass d where
f :: d -> Int
instance MyClass (Maybe d) where
f _ = 3
test1 :: Maybe d -> Int
test1 x = f x
This compiles just fine, and note that we do NOT need a (MyClass (Maybe d)) constraint on test1 because the compiler finds a matching instance for any Maybe d
.
We can even write an all-encompassing instance for class parameters that are type constructors:
class MyClass2 (a :: * -> *) where
g :: Tagged (a Int) Int
instance MyClass2 a where
g = Tagged 3
test2 :: Int
test2 = untag (g :: Tagged (Maybe Int) Int)
This also compiles fine, and test2 does not need a (MyClass2 Maybe) constraint, because the compiler finds a matching instance.
Consider the following toy code to compute the length of a (promoted) type list:
{-# LANGUAGE TypeOperators,
DataKinds,
KindSignatures,
GADTs,
FlexibleInstances,
FlexibleContexts,
ScopedTypeVariables #-}
import Data.Tagged
import Data.Proxy
data HList :: [*] -> * where
HNil :: HList '[]
HCons :: a -> HList as -> HList (a ': as)
class ListLen a where
len :: Tagged a Int
instance ListLen (HList '[]) where
len = Tagged 0
instance (ListLen (HList as)) => ListLen (HList (a ': as)) where
len = Tagged (1+(untag (len :: Tagged (HList as) Int)))
test3 :: Int
test3 = untag (len :: Tagged (HList '[Int, Double, Integer]) Int)
test4 :: (Proxy (HList qs)) -> Int
test4 (_ :: Proxy (HList qs)) = untag (len :: Tagged (HList qs) Int) -- error occurs here
This results in the error:
No instance for (ListLen (HList qs))
arising from a use of `len'
Possible fix: add an instance declaration for (ListLen (HList qs))
...
If we comment out the signature for test4
, GHCi infers the type as
test4 :: (ListLen (HList qs)) => (Proxy (HList qs)) -> Int
but this shouldn't be necessary. Clearly, I've written instances for ListLen
that match any conceivable type list: an 'empty list' case, and a 'cons' case. The problem remains the same if I change the kind of the ListLen
parameter to have kind [*]
(i.e., remove the HList
wrapper in ListLen
and its instances).
If we comment out test4
, test3
compiles and runs fine: since I (essentially) gave it explicit syntax ('[Int,Double,Integer]
) for how I constructed the type list, the compiler was able to find matching instances.
I'm attempting to write code that builds a type list for me, so I will not have to write out the explicit type list syntax. However, it seems that using explicit syntax is the only way GHC is able to match these comprehensive instances. Perhaps there's a case I'm missing? Syntax I'm not using?
What can I do to make GHC realize that I have an instance for everything of kind [*]
?
I'm using GHC 7.4.2. This might be related to a previous post about deconstructing non-promoted types. THE paper on type promotion can be found here.