raskell 0.1.0

Haskell-style functional programming for Rust
Documentation
# raskell

Haskell-style functional programming for Rust: combinators, type classes and
types.

Implemented: `hdo!`, do notation over `Option`, `Result` and `Vec`, with an
`async` mode. See the [roadmap](#roadmap) for what is planned.

```rust
use raskell::hdo;

let result = hdo! {
    x <- Some(10);
    y <- Some(20);

    let sum = x + y;

    guard sum > 5;

    pure sum * 2
};

assert_eq!(result, Some(60));
```

`hdo!` chains binds over `Option`, `Result` and `Vec`.

## Statements

| Syntax | Meaning |
| --- | --- |
| `pattern <- expression;` | Bind. Short-circuits on `None` / `Err`, iterates over a `Vec`. |
| `pattern <-? expression;` | Bind a `Result`, converting the error through `From`. |
| `pattern <- expression throw error;` | Bind a `Result` whose pattern may fail to match. |
| `pattern: Type <- expression;` | Bind with the bound value's type spelled out. |
| `guard condition;` | Yield `None` (or drop the list element) unless `condition` holds. |
| `guard condition throw error;` | Yield `Err(error)` unless `condition` holds. |
| `let pattern[: Type] = expression;` | Plain `let`, no monad involved. |
| `expression;` | An action, sequenced like a bind whose value is discarded. |
| `pure expression` | The block's result. Required, and must come last. |

`hdo!(async { .. })` accepts the same statements, minus list binds.

## Errors of different types

```rust
let result: Result<i32, Outer> = hdo! {
    x <-? inner();   // inner() -> Result<i32, Inner>, Outer: From<Inner>

    pure x * 2
};
```

## Lists

```rust
let pairs: Vec<(i32, i32)> = hdo! {
    x <- vec![1, 2, 3];
    y <- vec![10, 20];

    guard x + y > 12;

    pure (x, y)
};

assert_eq!(pairs, vec![(1, 20), (2, 20), (3, 10), (3, 20)]);
```

## Async

Wrapping the statements in `async { .. }` expands the block into an `async move`
block, so `.await` works anywhere inside it. The result is a plain future:
`.await` it or spawn it.

```rust
let result: Result<i32, ApiError> = hdo!(async {
    x <- fetch(10).await;
    y <-? from_store().await;      // ApiError: From<StoreError>

    guard x > 5 throw ApiError::TooSmall;

    pure x + y
})
.await;
```

Futures are not awaited implicitly; write the `.await` yourself.

## Limitations

* An `async` block binds `Option` and `Result` only: a list bind cannot
  short-circuit a future.
* Lists are bound as `Vec`; other iterators need `.collect()` first.

See the [crate documentation](https://docs.rs/raskell) for the full reference.

## Roadmap

### Functions and combinators

`map`, `filter`, `fold`, `compose`, `curry`, `flip`, `zip_with`, `maybe`,
`either`.

### Type classes, Rust-style

`Functor`, `Applicative`, `Monad`, `Foldable`, `Traversable`, `Semigroup`,
`Monoid`, as plain traits that compose with `Iterator` and the `std` traits.

Once `Monad` exists, `hdo!` should be defined in terms of it instead of the
per-type `HdoBind` impls it dispatches on today.

### Types

`Either`, `NonEmpty`, later `Reader`, `State`, `Writer`.

## License

MIT