[Announcement] comp-rs : Do-notation-like black magic on rust!

Announcing comp-rs

https://crates.io/crates/comp/

Do notation and List-comprehension for Option, Result and Iterator.

Pure-macro syntax extensions that easily combines wrapper type.

Example

comp delivers three macros : option!, result! and iter!, transforming the arrow(<-) statements into FP bind (flat_map).

Option

let option = option! {
  let a <- Some(1);
  let b <- Some(2);
  a + b
};

assert_eq!(option, Some(3));

Result

use std::fs::File;
use std::io;
use std::io::prelude::*;

let content: io::Result<String> = result! {
  let mut f <- File::open("foo.txt");
  let mut s = String::new();
  let _ <- f.read_to_string(&mut s);
  s
};

Iterator

let iter = iter! {
  let x <- 0..2u8;
  let y <- vec!['a', 'b'];
  (x, y)
};

for x in iter {
  println!("{:?}", x);
}

// Print (0, 'a') (0, 'b') (1, 'a') (1, 'b')

Though this is not a newly created crate, it has been refactor to be able to use in work. So I choose to announce it at this point and looking forward to your advice.

17 Likes

I am planing to extend it to work with futures-rs and I am wondering if it deserve.

2 Likes

That was my first thought, but it seems like it would be hard to make the "do block" resume after getting an Async::NotReady without coroutines or similar.

1 Like

No, it's quite simpler than you thought. We can just flat_map on futures or streams, then handle the details by themselves.

1 Like

I believe you can use ? with options, results and futures with the new Try trait — and it gives you way more flexibility, because you can do it in the middle of an expression or deep inside complex control flow.

The iterator variant is very interesting and useful though and can potentially greatly reduce boilerplate​.

If it's all just closures underneath, then you can't use return and break, right? Is there any syntax to make the closure move?

I believe you can use ? with options, results and futures with the new Try trait

Yes, I am also looking forward to Try to land. This lib provides another possibility to resolve callback hall problem. @alexcrichton also tries to explore an ergonomic way on this with [futures-await]
(GitHub - alexcrichton/futures-await). I want to provide the solution, and let others to choose their preference.

Besides, this lib have some advantages. For example, those macros can be use at item positions, which means we don't need to wraps code into function.

If it's all just closures underneath, then you can't use return and break, right?

Right. Because this is an idea from functional world, in which there is no Break or Return.

Is there any syntax to make the closure move?

These closures always capture variable by move.

1 Like

There's catch, but it's even further from stabilization.

You should document that.

I'm not sure it's a good choice, because most things in Rust don't move when they don't need to; you should at least document that.

That's because the flat_map always takes over ownership. This macro work just like what you will hand write.

1 Like

This is awwwsome! Thank you for this macro library.