instance Functor A where
instead of instance Functor (A a) where
.
Why does it work ?
I find this easier to understand using GHC's kinding system. Let's start from a simple case, and experiment in GHCi:
> :k Eq Int
Eq Int :: Constraint
This tells us that Eq Int
is a constraint, some property that might be verified during type checking. Indeed, if we type check (12 :: Int) == (42 :: Int)
, the compiler will verify that integers can be compared, resolving the constraint Eq Int
.
What is Eq
alone, the name of the class without the Int
parameter?
> :k Eq
Eq :: * -> Constraint
This tells us that Eq
can be thought of a function from types (*
is the kind of types) to constraint.
Indeed, in Eq Int
, Int
is a type, so we have Int :: *
making Int
a well-kinded argument to pass to Eq
.
Enough of type classes, what about type constructors?
> :k Maybe Int
Maybe Int :: *
No surprise, Maybe Int
is a type
> :k Maybe
Maybe :: * -> *
Maybe
instead, is a function from types to types (*->*
). This is indeed what the Maybe
type constructor does: mapping a type (Int
) to a type (Maybe Int
).
Back to the original question. Why can't we write instance Functor (A a)
but we can instead write instance Functor A
? Well, we have that
> :k A Int
A Int :: *
> :k A
A :: * -> *
and, most importantly,
> :k Functor
Functor :: (* -> *) -> Constraint
This tells us the the kind of the Functor
type class is not the same kind of the Eq
type class. Eq
expects a type as an argument, while Functor
expects something of kind (* -> *)
as an argument. A
fits that kind, while A Int
does not.
This happens when, in the definition of the class, the argument is applied to some other type. E.g.
class C1 a where
foo :: a -> Bool
results in C1 :: * -> Constraint
. Instead,
class C2 f where
bar :: f Int -> Bool
results in C2 :: (* -> *) -> Constraint
, since f
is not itself used as a type, f Int
is, so f
must be a parameterized type of kind * -> *
.
fmap
(inFunctor
isfmap :: (a -> b) -> f a -> f b
, so here we applya
to the type constructorA
, given that we would makeA Int
a functor, how should we handef a
(soA Int a
)? – Immolatef
is basically a function that takes a type and constructs a new type. – Immolateinstance Functor A where
its like we partially applyA
? and we supply the type when we callfmap
? (Not sure if i understood) – Conjurationf
is a "function" that transforms a type (likeInt
) into a typeA Int
. – ImmolateA [something]
and we callfmap A [something_else]
it crashes . Does it mean that in the instance implementation we canfill
anytype
parameter or let it free: Ex:instance T a b c where
,instance T Int b c
,instance T Int b Int
..etc? – Conjurationotherfmap :: (Int -> String) -> f Int -> f String
, so the parameter is not per se free, but forFunctor
, yes it is free. – Immolate