# Simple introduction to monads in OCaml posted November 2022

I'm not a language theorist, and even less of a functional programming person. I was very confused trying to understand monads, as they are often explained in complicated terms and also mostly using haskell syntax (which I'm not interested in learning). So if you're somewhat like me, this might be the good short post to introduce you to monads in OCaml.

I was surprised to learn that monads are really just two functions: `return`

and `bind`

:

```
module type Monads = sig
type 'a t
val return : 'a -> 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
end
```

Before I explain exactly what these does, let's look at something that's most likely to be familiar: the `option`

type.

An option is a variant (or enum) that either represents nothing, or something. It's convenient to avoid using real values to represent emptiness, which is often at the source of many bugs. For example, in languages like C, where `0`

is often used to terminate strings, or Golang, where a `nil`

pointer is often used to represent nothing.

An `option`

has the following signature in OCaml:

`type 'a option = None | Some of 'a`

Sometimes, we want to chain operations on an option. That is, we want to operate on the value it might contain, or do nothing if it doesn't contain a value. For example:

```
let x = Some 5 in
let y = None
match x with
| None -> None
| Some v1 -> (match y with
| None -> None
| Some v2 -> v1 + v2)
```

the following returns nothing if one of `x`

or `y`

is `None`

, and something if both values are set.

Writing these nested match statements can be really tedious, especially the more there are, so there's a `bind`

function in OCaml to simplify this:

```
let x = Some 5 in
let y = None in
Option.bind x (fun v1 ->
Option.bind y (fun v2 ->
Some (v1 + v2)
)
)
```

This is debatably less tedious.

This is where two things happened in OCaml if I understand correctly:

- Jane street came up with a ppx called ppx_let to make it easier to write and read such statements
- OCaml introduce the same feature without ppxs

Let's explain the syntax introduced by OCaml first.

To do this, I'll define our monad by extending the OCaml `Option`

type:

```
module Monad = struct
type 'a t = 'a option
let return x = Some x
let bind = Option.bind
let ( let* ) = bind
end
```

The syntax introduced by Ocaml is the `let*`

which we can define ourselves. (There's also `let+`

if we want to use that.)

We can now rewrite the previous example with it:

```
open Monad
let print_res res =
match res with
| None -> print_endline "none"
| Some x -> Format.printf "some: %d\n" x
let () =
(* example chaining Option.bind, similar to the previous example *)
let res : int t =
bind (Some 5) (fun a -> bind (Some 6) (fun b -> Some (a + b)))
in
print_res res;
(* same example but using the let* syntax now *)
let res =
let* a = Some 5 in
let* b = Some 6 in
Some (a + b)
in
print_res res
```

Or I guess you can use the `return`

keyword to write something a bit more idiomatic:

```
let res =
let* a = Some 5 in
let* b = Some 6 in
return (a + b)
in
print_res res
```

Even though this is much cleaner, the new syntax should melt your brain if you don't understand exactly what it is doing underneath the surface.

But essentially, this is what monads are. A container (e.g. `option`

) and a `bind`

function to chain operations on that container.

Bonus: this is how the jane street's ppx_let syntax works (only defined on `result`

, a similar type to `option`

, in their library):

```
open Base
open Result.Let_syntax
let print_res res =
match res with
| Error e -> Stdio.printf "error: %s\n" e
| Ok x -> Stdio.printf "ok: %d\n" x
let () =
(* example chaining Result.bind *)
let res =
Result.bind (Ok 5) ~f:(fun a ->
Result.bind (Error "lol") ~f:(fun b -> Ok (a + b)))
in
print_res res;
(* same example using the ppx_let syntax *)
let res =
let%bind a = Ok 5 in
let%bind b = Error "lol" in
Ok (a + b)
in
print_res res
```

You will need to following `dune`

file if you want to run it (assuming your file is called `monads.ml`

):

```
(executable
(name monads)
(modules monads)
(libraries base stdio)
(preprocess
(pps ppx_let)))
```

And run it with `dune exec ./monads.exe`