I have been inspecting the type of Lens
to understand it and have trouble figuring out the resulting type of partial application there.
Initial type is like this: type RefF a b = forall f. Functor f => (b -> f b) -> (a -> f a)
The above type applied for Identity
functor becomes like this:
(b -> Identity b) -> (a -> Identity a)
Their modify function is defined like this:
modify :: RefF a b -> (b -> b) -> a -> a
modify r m = runIdentity . r (Identity . m)
I decompose the above definition individually to understand it better.
From above, the type of Identity . m
is b -> Identity b
I even verified this using the typechecker:
check1 :: (b -> b) -> b -> Identity b
check1 m = Identity . m
Now, I try to formulate the type of r (Identity . m)
. Here is where my mind becomes empty. The actual result of the partial application of r (Identity . m)
seems to be a -> Identity a
as typechecked below:
check2 :: RefF a b -> (b -> Identity b) -> a -> Identity a
check2 r che = r che
How does one figure this out mentally ? When I try to partially apply che
to r
, it doesn't seem to fit:
The type of `r` is : (b -> Identity b) -> (a -> Identity a)
The type of `che` is : (b -> Identity b)
How does one trace out that the partial application of r che
is (a -> Identity a)
When I try to partially apply che to r, it doesn't seem to fit:
r
has type
(b -> Identity b) -> (a -> Identity a)
which means its first argument needs to have type (b -> Identity b)
.
che
has type
(b -> Identity b)
Just as r
required, therefore r che
will work and have type (a -> Identity a)
.
After applied to the third argument, suppose it has been named arg
, of modify
, this arg
has type a
, r (Identity . m) arg
will have type Identity a
, after applied runIdentity
on it, the result will have type a
.
type RefF a b = forall f. Functor f => (b -> f b) -> (a -> f a)
modify :: RefF a b -> (b -> b) -> a -> a
modify r m = runIdentity . r (Identity . m)
You could infer the type of modify r m
like this:
r
has type RefF a b
, which is (b -> f b) -> (a -> f a)
m
has type b->b
Identity
has type forall a. a -> Identity a
, therefore Identity . m
has type b -> Identity b
r (Identity . m)
has type a -> Identity a
, because f
must be Identity
runIdentity
has type forall a. Identity a -> a
, therefore runIdentity . r (Identity . m)
has type a -> a