FP is all about composition - how to combine expressions to larger ones that mean what you want.
Mathematical functions are like A => B
and then compose really nicely, A=>B
and B=>C
compose to give you A => C
Category theory is the study of composition, generalizes that notion of composition. It notices that a -> f b
shaped functions can still compose for some f
- Monads. a -> f b
and b -> f c
give you a -> f c
- that's flatMap/bind/>>=/whatever you call it
The "Kleisli" category is the name for the category of composition on that shape.
Kleisli types, aka "reader monad" or ReaderT more generally, are how we encode that in FP languages.
Where a -> b
is a monad mapping on b
, if you tried using that ->
monad for a -> f b
you'd be mapping on f b
, not b
. Kleisli/ReaderT shapes let you change the monad being used so that given shapes like a -> f b
, you map on the b
String -> Parser (Array Char)
is such a shape / a=String f=Parser b=Array Char, then you can use Kleisli/ReaderT to recover the ability to map
on the Array Char
part, which is exactly the operation you want
import Data.Generic.Rep as GR
import Data.Generic.Rep.Show (genericShow)
data IntOrBoolean2
= Int2 Int
| Boolean2 Boolean
-- note the underscore at the end for the `rep` parameter of class Generic
derive instance genericIntOrBoolean2 :: GR.Generic IntOrBoolean2 _
instance showIntOrBoolean2 :: Show IntOrBoolean2 where
show = genericShow
-- now we get a Show