I'm learning about monads in Haskell, I understood why they are useful, I understood in general what bind, join, return do.
I also looked at basic usage examples for the basic reader / writer / state / list / maybe monads.
Still, being a beginner, I still don't feel I have a grip on what the "run" function (e.g. runState, runReader, runWriter) mean in general. It does not seem to have a generic signature like the above functions, and I don't get it if it's definable / makes sense for all monads.
The >>=function is known as "bind" because it binds the value in a monad container to the first argument of a function. By adding logic to the binding function, a monad can implement a specific strategy for combining computations in the monad.
They have three properties that make them especially useful: Modularity - They allow computations to be composed from simpler computations and separate the combination strategy from the actual computations being performed. Flexibility - They allow functional programs to be much more adaptable than equivalent programs written without monads.
Less obviously, monads also promote modularity by allowing you to vary the monad in which a computation is done to achieve different variations of the computation. This is achieved by writing functions which are polymorphic in the monad type constructor, using the (Monad m) =>, (MonadPlus m) =>, etc. class constraints.
The MonadStateclass provides a standard but very simple interface for State monads. The getfunction retrieves the state by copying it as the value. The putfunction sets the state of the monad and does not yield a value. There are many additional functions provide which perform more complex computations built on top of getand put.
The run
function for most monads is actually just an artifact of how the monad is internally represented; For example, the Reader
monad could theoretically be represented as just
type Reader r a = r -> a
State
as
type State s a = s -> (s, a)
and so on. However, if we did that then we couldn't provide different typeclass (including Monad
) implementations for Reader
and State
as they'd both just be represented by (->)
.
-- that is, if we wrote
instance Functor (Reader r)
-- ....
and
instance Functor (State s)
-- ...
our compiler would complain we're trying to give two different Functor
implementations for (->) a
.
So instead of type
we just more or less write the same thing with newtype
, e.g.
newtype Reader r a = Reader { runReader :: r -> a }
or
newtype State s a = State { runState :: s -> (s, a)}
As you can see, the run
functions don't actually do anything here, they just "unwrap" the newtype so we can get the underlying value.
(actual implementations may involve monad transformers and therefore look a bit more complicated, but they're essentially still doing the same thing).
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