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 common derives like Debug
, Clone
, Eq
, Ord
, Hash
, etc., and enum
s have all their members pub use
d:
use *;
monad!
// And these just work:
// Monad
assert_eq;
assert_eq;
assert_eq;
// Functor
assert_eq!;
assert_eq!;
Examples
Catch panic
s without worrying about the details:
assert_eq!;
assert_eq!;
The logic of Haskell lists with the speed of Rust vectors:
// 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 = consume; // List<List<u8>>
let joined = li.join; // --> List<u8>!
assert_eq!;
Plus, we automatically derive QuickCheck::Arbitrary
and property-test the monad and functor laws.
Just run cargo test
and they'll run alongside all your other tests.
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 }