rsmonad: Monads in stable Rust (+ Applicative, Alternative, Functor, Monoid, ...)
Hey all! First post :)
I fell in love with Haskell's zero-boilerplate style and mathematical purity last semester (our course is apparently famous?), but when running programs, I missed control over what happens behind the scenes. I've now fallen way harder in love with Rust, so I thought I'd try to marry the two!
A quick example of more than a few higher-kinded types without annotations:
assert_eq!(
vec![
|| "this string isn't a number",
|| "67",
|| "that was, but not binary",
|| "1010101010",
|| "that was, but more than 8 bits",
|| "101010",
|| "that one should work!",
|| panic!("lazy evaluation!"),
]
.fmap(|x| move || u8::from_str_radix(x(), 2).ok())
.asum(),
Some(42)
);
Pythagoraean triples with desugared list comprehension:
assert_eq!(
list![1..20] >> |x| {
list![{ x }..20] >> |y| {
list![{ y }..20] >> |z| {
guard::<List<_>>(x * x + y * y == z * z) >> |_| {
list![(x, y, z)]
}
}
}
},
list![ // Including "non-primitive" (i.e. multiples of smaller) triples
(3, 4, 5),
(5, 12, 13),
(6, 8, 10),
(8, 15, 17),
(9, 12, 15)
]
);
The library simulates HKTs with a pattern like this:
trait Hkt<A> {
type Hkt<B>: Hkt<B, Hkt<A> = Self>;
// ...
}
You repeat yourself exactly once, but nothing will compile unless the two are identical. Then, if we have HA: Hkt<A>, we can use HA::Hkt<B>. This should be extensible to any finite number of type arguments. Honestly, most impressive is that Rust's type system can do all this; I only nudged it a bit.
Here's the open-source (MPL*) crate in its so-far entirety: GitHub/crates.io
Hope you enjoy and find it useful! If you're so inclined, put it to good use in your own projects, push it to its limits, and let me know where the holes are. If I'm not the first to do any of this, please let me know as well! This was mostly for my own practice, so I raw-dogged it without searching for prior solutions.
*Edited to change license from LGPL to MPL (to allow static linking)—thanks, chayleaf!