### 3 releases

0.1.2 | May 19, 2023 |
---|---|

0.1.1 | May 19, 2023 |

0.1.0 | May 18, 2023 |

#**12** in #proofs

**LGPL-3.0-or-later**

47KB

894 lines

# 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 `>>=`

instead of `consume`

(keyword).
For functors, you can use `return`

or `fmap``(`f`,` x`)`

, or you can `x .fmap(f)`

*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

and you get all its superclasses like `monad!` `{` `...`

for free, plus common derives like `Functor`

, `Debug`

, `Clone`

, `Eq`

, `Ord`

, etc., and `Hash`

s have all their members `enum`

d:`pub` `use`

`use` `rsmonad``::``prelude``::``*``;`
`monad!` `{`
`enum` `Maybe`<A> `{`
Just`(`A`)``,`
Nothing`,`
`}`
`fn` `bind``(``self`, f`)`` ``{`
`match` `self` `{`
Just`(`a`)` `=>` `f``(`a`)``,`
Nothing `=>` Nothing`,`
`}`
`}`
`fn` `consume``(`a`)`` ``{`
Just`(`a`)`
`}`
`}`
`//` And these just work:
`//` Monad
`assert_eq``(`Just`(``4``)` `>``>` `|`x`|` `u8``::`checked_add`(`x`,` `1``)``.``into``(``)``,` Just`(``5``)``)``;`
`assert_eq``(`Nothing `>``>` `|`x`|` `u8``::`checked_add`(`x`,` `1``)``.``into``(``)``,` Nothing`)``;`
`assert_eq``(`Just`(``255``)` `>``>` `|`x`|` `u8``::`checked_add`(`x`,` `1``)``.``into``(``)``,` Nothing`)``;`
`//` Functor
`assert_eq!``(`Just`(``4``)` `|` `u8``::`is_power_of_two`,` Just`(``true``)``)``;`
`assert_eq!``(`Nothing `|` `u8``::`is_power_of_two`,` Nothing`)``;`

## Examples

Catch

s without worrying about the details:`panic`

`fn` `afraid_of_circles``(``x``:` `u8``)`` ``->` `BlastDoor``<``(``)``>` `{`
`if` x `==` `0` `{` `panic!``(``"`aaaaaa!`"``)``;` `}`
Phew`(``(``)``)`
`}`
`assert_eq!``(`
Phew`(``42``)` `>``>` afraid_of_circles`,`
Phew`(``(``)``)`
`)``;`
`assert_eq!``(`
Phew`(``0``)` `>``>` afraid_of_circles`,`
Kaboom`,`
`)``;`

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
`fn` `bunny``(``s``:` `&``str``)`` ``->` `List``<``&``str``>` `{`
List`(``vec!``[`s`,` s`,` s`]``)`
`}`
`assert_eq!``(`
`List``::`consume`(``"`bunny`"``)` `>``>` bunny`,`
List`(``vec!``[``"`bunny`"``,` `"`bunny`"``,` `"`bunny`"``]``)``,`
`)``;`
`assert_eq!``(`
`List``::`consume`(``"`bunny`"``)` `>``>` bunny `>``>` bunny`,`
List`(``vec!``[``"`bunny`"``,` `"`bunny`"``,` `"`bunny`"``,` `"`bunny`"``,` `"`bunny`"``,` `"`bunny`"``,` `"`bunny`"``,` `"`bunny`"``,` `"`bunny`"``]``)``,`
`)``;`

And even the notoriously tricky

-in-terms-of-`join`

with no type annotations necessary:`bind`

`let` li `=` `List``::`consume`(``List``::`consume`(``0_``u8``)``)``;` `//` List<List<u8>>
`let` joined `=` li`.``join``(``)``;` `//` --> List<u8>!
`assert_eq!``(`joined`,` `List``::`consume`(``0_``u8``)``)``;`

Plus, we automatically derive

and property-test the monad and functor laws.
Just run `QuickCheck ::`Arbitrary

`cargo`` test`

and they'll run alongside all your other tests.## Sharp edges

Right now, you can use

as sugar for `>``>`

only when you have a `bind`*concrete instance* of

like `Monad`

but not a general `Maybe`

.
The latter still works but requires an explicit call to `<`M`:` `Monad <A>`

`>`

`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``]`

`#!``[``no_std``]`Disable default features:

`# Cargo.toml`
`[``dependencies``]`
`rsmonad = { version = "*", default-features ``=` `false` }

#### Dependencies

~355–780KB

~19K SLoC