I have typed a little monadic programming tutorial.

https://www.sinerj.org/~loyer/monadic_programming/monadic_programming/index.html

Hope this helps. Your comments are welcomed.

I have typed a little monadic programming tutorial.

https://www.sinerj.org/~loyer/monadic_programming/monadic_programming/index.html

Hope this helps. Your comments are welcomed.

1 Like

I have added an `option`

monad section. `option`

monad is less powerful than the `list`

monad (an option is like a list of zero or one item), but this monad can be very handy with functions like `Base.Hashtbl.find`

or `Stdlib.Hashtbl.find_opt`

which returns an option we donâ€™t wanâ€™t to match with `Some x`

explicitly.

Nicely done.

Do you have anything to say about other monads? Iâ€™m thinking about state, reader, writerâ€¦

The state monad looks particularly interesting to me but Iâ€™ve only toyed with it thus far.

Hi,

Thanks for the idea. I donâ€™t think these monads are implemented in Base/Core. However, implementing them should not be difficult. I could propose a section â€śimplementing its own monadâ€ť.

About the State monad, I am puzzled about its usefulness in Ocaml since it is made to deal with the absence of mutable field (ref contents for example). And if my memory is ok, dealing with two states is rather cumbersome.

Regarding Lwt, instead of starting with `let%lwt`

and then explaining that it behaves the same as `let*`

in the previous sections, I would suggest starting by defining `let*`

(`Lwt.bind`

), and then later explaining that Lwt has a preprocessor that provides the `let%lwt`

construct, which is just `let*`

with better behavior with respect to exception backtraces. In particular, none of your Lwt examples actually require on the preprocessor, so you could move the whole explanation to an appendix, thus avoiding polluting your explanation about monadic programing.

2 Likes

Although depending on what you are doing, the limitation to only 1 item at most can be an important feature. Like you can see the option monad as a list monad with an added powerful invariant that the item count never exceeds 1.

So I wouldnâ€™t say `option`

is â€śless powerfulâ€ť than `list`

.

1 Like

I have included a section about the state monad. This monad is interesting since the different monads `get`

, `put x`

are not just plain values but functions which get the state as an argument even if we donâ€™t pass explicitly this argument (it is the job of run or bind).

I have applied other proposals.

It can be useful, for instance when you combine it with a continuation monad (which gives what I call a choice monad, but I just found it is also called a select monad).

This is a thing that can be needed when implementing a symbolic interpreter (and even more when you want the interpreter to be able to do both concrete or symbolic execution and thus is a functor parameterized by this monad). The one linked is doing multi-core exploration so it is a bit more complex.

1 Like

Iâ€™m not sure if thatâ€™s what you meant, but Iâ€™ve learned lately that Haskell does have mutable variables. So Iâ€™m not sure that the use of this technique is motivated by the absence of mutable fields.

Iâ€™ve only scratched the surface (via the preface library), but I like the idea of describing the mutation of state as a pure function. I suspect it could help design better programs as well as making testing easier. Plus, overall, I like the constraint a monad enforces.

Suppose Iâ€™ve got a random number generator.

```
val random : int -> int
```

I can now describe a pure function that produces a random int.

```
let rand_int : int Random.t =
let* seed = Random.get in
let new_seed = random seed in
let* () = Random.set new_seed in
Random.return new_seed
;;
```

I can derive another pure function from it

```
let rand_bool : bool Random.t =
Random.map
(fun n -> n mod 2 = 0)
rand_int
;;
```

Or even more complicated structures:

```
let rand_tup3 : (int * bool * int) Random.t =
let* a = rand_int in
let* b = rand_bool in
let* c = rand_int in
Random.return (a, b, c)
;;
```

Those functions are purely descriptive, which I find quite fascinating.

The mutable equivalent would be:

```
let gen_int =
let seed = ref 0 in
fun () ->
seed := random !seed;
!seed
;;
let gen_bool () =
(gen_int ()) mod 2 = 0
let rand_tup3 : int * bool * int =
let a = gen_int () in
let b = gen_bool () in
let c = gen_int () in
(a, b, c)
;;
```

Which is roughly the same amount of code, but with less meaning and guaranties.

I havenâ€™t fully connected the dots though, I would gladly learn more.

Thanks for your input @zapashcanon , and thanks @Frederic_Loyer for the article update.

Thanks for the article. We note that even with the mutable variable, a monad sequence is involved (`do ... r <- readIORef 0 ...`

)

I donâ€™t know when it has been introduced. I have looked at the Haskell language more than 10 years ago and didnâ€™t remember of it. Using state monad is ok when there is only one variable to deal withâ€¦ Hugs doesâ€™nt support it.

Trivial nit: doesnâ€™t work very well on my android mobile.

What I would like to see is some kind of â€śmotivationâ€ť section. What problems do monads solve? What can I do with a monad that I cannot do otherwise? Are they merely a convenience or is something more substantial involved?

A difficult questionâ€¦ Haskell has introduced it by necessity since no side effect where allowed and modads were introduced to emulate side effects. On the previous quoted article, Control.Data.IORef and Data.STRef are only accessible in a monad context. OCaml has not such constraints.

However, the option section proposes a way of sequencing functions which may return `Some`

thing, or return `None`

. Monads may render things quite easy.

With Lwt, monads are used to modelise a sequence of IO and schedule them (a bit anachronic when Ocaml 5.0.0 and Eio is outâ€¦ but there are still Lwt code to deal with)

It can be interesting to enumerate other interesting pro.

So, I once spent a lot of time trying to understand the monad concept (I even read Moggiâ€™s papers, or at least ran my eyes over them) without *really* grokking the stuff. But what I took away was that it boils down to sequencing or chaining stuff that does not â€śnaturallyâ€ť support that. Ie turning non-monoids into monoids, something like that. Am I close?

For example Io monads do not eliminate side effects, they just make them manageable by enforcing sequentiality.

Which leads to a related question: in what circumstances does it make sense to use monads when side effects are not an issue?

Yes, it enforces sequentiality since the bind operator (>>=) get the return value of the first argument and pass it as an argument to the second which is a function.

However, we never have a sequence issue in OCaml : `a; b`

is always executed in the right order.

I guess the main added value from a OCaml point of vue is when the bind and run functions are doing some interesting scheduling things. In my page, there are 2 such examples: option and Lwt,

stm: Software Transactional Memory - FP Complete gives and interesting other examples where a monad schedule something multiple times. But I am not sure it applies to OCaml (Kcas doesnâ€™t seem to follow a monadic pattern).

I am trying to propose a new design of the state monad.

Something simple, base on a type

```
type 't state_monad =
Result of 't | Get | Put of 't | Bind of ('t -> ... state_monad)
```

However, I canâ€™t figure out the type it: if I instanciate the `...`

in the Bind constructor, I had to add parametric types in the front of monadâ€¦ then they are needed again inside Bindâ€¦ I canâ€™t write this definition as I want.

I have upgraded the introduction with the interest of monads (mainly with lwtâ€¦ its use is mandatory with some application server, and error handling where it can be convenient - see Caqti/Rapper tutorial- , and add a light section about the `result`

monad.

I have look at Monads Â· OCaml Documentation latelyâ€¦ and I find many differences of approach between mine version and the ocaml.org version.

I guess a mix of the two versions would be interesting. The ocaml.org version is more precise in the introductionâ€¦ and my version goes further with some convenient notations : `let*`

, `let%lwt`

(`lwt_ppx`

), `let%bind`

(`ppx_let`

)â€¦ (even Haskell has a corresponding notation (`do a <- b...;b <- ...`

) why not introduce them ?).

The approches are quite different: ocaml.org has a more pedagogical approach (it creates from scratch a Maybe/Option monad) and my tutorial is more â€śpracticalâ€ť (letâ€™s use the Option monad from Jane Street), even if a â€ścustom monadâ€ť section is proposed.

Since the added value of my tutorial is mainly about the reuse of available notations, a second page about â€śMonads complements: convenient notationâ€ť could be adequate (no need to patch the Monads page which is tagged C3110 which bring some attribution issue). However, the operators page does introduce `(let*)`

and `bind`

without a link to the monad page.

If you havenâ€™t seen it, I enthusiastically recommend Std (monads.Monads.Std) for an intro to the concept for working programmers. Imo, it is a really nice way of helping develop the intuition for monadic constructs as a way of parameterizing computational contexts.

Letâ€™s not. For a tutorial on ocaml.org, letâ€™s instead use the `Option`

monad from the standard library. Or better still, use the `Result`

monad from the standard library with the `let*`

operator, and present it as an alternative to the use of exceptions. The `Result`

monad with the `let*`

operator in my view presents a compelling first introduction for beginners to the use of monads in OCaml.

4 Likes

Interesting, really ! The introduction goes from the pseudocode `a := b; expr`

, then introduces the `bind`

and its corresponding `>>=`

. I guess it quite nice in a pedagic way.

But I will go further and introduced the `let a = b in expr`

which:

- goes back to the original idea,
- is imported by a
`open Monads.Std.Monad.Option`

or something like this

My understanding is that Monads are made to simplify the programming, then the `bind`

function is important to understant what happens under the hood, but the `let*`

is important to present the program in a elegant way.

The transformer parts is interestingâ€¦ but lack some example and seems a bit too abstract. The Lwt/Result combo use case could be interesting (I donâ€™t know if a `lift`

could have solved any issue. I note that a Lwt_result monad is introduced to solve our problems).