Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intuition for "run" function of monads

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.

like image 920
jack malkovick Avatar asked Feb 05 '19 13:02

jack malkovick


People also ask

What does >>= do in a monad?

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.

What are the advantages of monads in functional programming?

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.

How do monads promote modularity?

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.

What is the use of monadstateclass?

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.


1 Answers

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).

like image 116
Cubic Avatar answered Oct 22 '22 04:10

Cubic