Monads, Functors, & More to Come in Rust
Haskell-style monads with Rust syntax.
Syntax
Rust requires >>= to be self-modifying, so we use >> instead of >>= and consume instead of return (keyword).
For functors, you can use fmap(f, x) or x.fmap(f), or you can pipe it: x | f | g | ....
At the moment, Haskell's monadic >> seems unnecessary in an eager language like Rust, but I could easily be overlooking something!
Use
Just write a monad! { ... and you get all its superclasses like Functor for free, plus property-based tests of the monad laws:
use *;
monad!
// And these just work:
// Monad
assert_eq;
assert_eq;
assert_eq;
// Functor
assert_eq!;
assert_eq!;
Examples
The logic of Haskell lists with the speed of Rust vectors:
use *;
let li = list!;
assert_eq!;
Catch panics without worrying about the details:
assert_eq!;
assert_eq!;
N-fold bind without type annotations:
// from the wonderful Haskell docs: https://en.wikibooks.org/wiki/Haskell/Understanding_monads/List
assert_eq!;
assert_eq!;
And even the notoriously tricky join-in-terms-of-bind with no type annotations necessary:
let li = list!; // List<List<u8>>
let joined = li.join; // --> List<u8>!
assert_eq!;
Sharp edges
Right now, you can use >> as sugar for bind only when you have a concrete instance of Monad like Maybe but not a general <M: Monad<A>>.
The latter still works but requires an explicit call to m.bind(f) (or, if you don't use the trait, Monad::<A>::bind(m, f)).
This should be fixed with the Rust's non-lifetime binder feature when it rolls out.
#![no_std]
Disable default features:
# Cargo.toml
[]
= { = "*", = false }