# Monad laws in Rust

Just read Rust's Try v2 proposal, and this example caught my attention.

```
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
let mut accum = init;
while let Some(x) = self.next() {
accum = f(accum, x)?;
}
try { accum }
}
```

Notice how `try { accum }`

is generic w.r.t. the return type. This looks pretty monadic and, unsurprisingly, monadic operations can be translated to this Rust representation mechanically.

Haskell | Rust |
---|---|

`return x` | `try { x }` |

`m >>= f` | `try { f(m?)? }` |

We can translate the three monad laws into Rust code:

Name | Haskell left | Haskell right | Rust left | Rust right |
---|---|---|---|---|

Left identity | `return a >>= h` | `h a` | `try{h(a?)?}` | `h(a)` |

Right identity | `m >>= return` | `m` | `try{try{m?}?}` | `m` |

Associativity | `(m >>= g) >>= h` | `m >>= (\x -> g x >>= h)` | `try{h(try{g(m?)?}?)?}` | `try{E(m?)?}` |

where `E`

stands for `|x|try{h(g(x)?)?}`

. (I can't put it in the table because it confuses Markdown, ugh.)

Can we prove them in Rust? Right identity is a direct consequence. Quoting the RFC,

```
<T as Try>::from_output(x).branch() ⇒ ControlFlow::Continue(x) (aka try { x }? ⇒ x)
```

Associativity is also obvious. Don't know the proof of left identity yet, because you can't simply unwrap `try{x?}`

: `h(a?)`

is distinctly not `h(a)`

.

Loading Disqus...(Alternatively, drop me an E-mail to comment on this post.)