While trying to find a haskell monad that can be executed stepwise / allows threading, I discovered the free monad
data Free f a = Return a | Roll (f (Free f a))
with its monad instance
instance (Functor f) => Monad (Free f) where
return = Return
Return x >>= f = f x
Roll action >>= f = Roll $ fmap (>>= f) action
and its functor instance
instance (Functor f) => Functor (Free f) where
fmap f (Return x) = Return (f x)
fmap f (Roll x) = Roll $ fmap (fmap f) x
I know that every monad is an applicative functor with pure = return
and (<*>) = ap
.
For me, applicative functors are conceptually harder than monads. For a better understanding of applicative functors, I like to have the applicative instance without resorting to ap
.
The first line for <*>
is easy:
instance (Applicative f) => Applicative (Free f) where
pure = Return
Return f <*> x = fmap f x -- follows immediately from pure f <*> x = f <$> x
--Roll f <*> x = Roll $ (fmap ((fmap f) <*>)) x -- wrong, does not type-check
How to define Roll f <*> x
in basic terms with fmap
and <*>
?
Monads are not a replacement for applicative functors Instead, every monad is an applicative functor (as well as a functor). It is considered good practice not to use >>= if all you need is <*>, or even fmap.
A functor takes a pure function (and a functorial value) whereas a monad takes a Kleisli arrow, i.e. a function that returns a monad (and a monadic value). Hence you can chain two monads and the second monad can depend on the result of the previous one.
In Haskell, an applicative is a parametrized type that we think of as being a container for data of that type plus two methods pure and <*> . Consider a parametrized type f a . The pure method for an applicative of type f has type. pure :: a -> f a. and can be thought of as bringing values into the applicative.
A functor is a data type that implements the Functor typeclass. An applicative is a data type that implements the Applicative typeclass. A monad is a data type that implements the Monad typeclass. A Maybe implements all three, so it is a functor, an applicative, and a monad.
Will this do?
instance (Functor f) => Applicative (Free f) where
pure = Return
Return f <*> as = fmap f as
Roll faf <*> as = Roll (fmap (<*> as) faf)
The plan is to act only at the leaves of the tree which produces the function, so for Return
, we
act by applying the function to all the argument values produced by the argument action. For Roll
, we just do to all the sub-actions what we intend to do to the overall action.
Crucially, what we do when we reach Return
is already set before we start. We don't change our plans depending on where we are in the tree. That's the hallmark of being Applicative
: the structure of the computation is fixed, so that values depend on values but actions don't.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With