Square is a monad join of a function
How do you implement square (or double) using Monads?
Quite simple: Use the monad instance of a function and then `join` on a function that returns a function.
How on earth does that work?
You know the signature of Monad join.
join :: Monad f => f (f a) -> f a
join ffa = ffa >>= id
Consider data Optional a = Full a | Empty
has a monad instance. This implies:
>> join (Full (Full 1))
Full 1
In this case,f
is Optional
, and ffa
is Full (Full 1)
When you replace Optional
to be a function f: t -> a
, then ffa
is f: t -> ( t -> a )
.
As an example :
>> ffa = \x -> (\y -> x * y)
>> ffa 2 3
6
>>
ffa = \x -> (\y -> x * y))
is same as ffa = (*)
Thinking along the same lines, calling join
on ffa
to return fa
means converting t-> (t -> a)
to t -> a
Let’s do that:
>> :type (join (*))
(join ffa) :: Num a => a -> a
join (*)
returns a function Int -> Int
effectively.
>> join (*) 10
100
This implies:
>> square = join (*)
>> double = join (+)
Yea, that was more of a fun. But you can sort of guess that monad instance of a function (->) t
involves passing the same argument twice to a binary function. I will explain this blog with some Scala
later , although I found it a little less intuitive considering I cannot write join(*)
or (*).join
after the required imports from cats/scalaz. But it will still be a good exercise.