functype
Scala-inspired functional programming library for Rust.
Brings the ergonomics of Scala's type system — Either, Validated, IO, do-notation — to Rust, without fighting the borrow checker.
use *;
use IO;
use fdo;
let result = fdo! ;
assert_eq!;
Crates
| Crate | Description |
|---|---|
functype |
Umbrella crate — re-exports everything |
functype-core |
Core types: Either, Validated, Try, NonEmptyVec, persistent collections, fdo! macro |
functype-io |
Lazy IO effect type with resource safety and async interop |
Core Types
Either<L, R>
Right-biased disjoint union. Short-circuits on Left.
use *;
use fdo;
let result: = fdo! ;
assert_eq!;
Full API: map, flat_map, bimap, fold, swap, filter_or_else, ap, zip, conversions to/from Result and Option.
Validated<E, A>
Applicative validation that accumulates all errors instead of short-circuiting. Errors are collected in NonEmptyVec<E> — guaranteed non-empty at the type level.
use *;
let result = validate_name.zip;
// Both errors collected, not just the first
assert!;
IO<A>
Lazy, composable effect type. Nothing executes until .run().
use IO;
let io = IOeffect.map;
// Nothing printed yet
let result = io.run.unwrap; // prints "side effect!", returns 84
Why IO<A> instead of three type parameters:
- No R (environment): Rust has compile-time DI via function arguments + trait bounds.
- No E (typed error):
Resultalready handles typed errors. For typed errors, useIO<Result<A, E>>— opt-in, not mandatory. - One type param: Clean signatures.
io.map(|x| x + 1)without error type propagation everywhere.
Constructors
IOsucceed // pure value
IOfail // pure error
IOeffect // infallible side effect
IOeffect_result // fallible side effect
IOfrom_result // lift Result
IOfrom_option // lift Option
IOfrom_either // lift Either
Combinators
io.map // transform success
io.flat_map // chain effects
io.zip // combine into tuple
io.zip_with // combine with function
io.then // sequence, discard first
io.tap // side effect, return original
Error Handling
io.map_error // transform error
io.catch // recover
io.or_else // fallback on error
io.either // IO<Either<Error, A>> (infallible)
IOretry // retry up to 3 times
Resource Safety
IObracket;
io.ensuring // finalizer runs on both success and error
Async Interop
IOfrom_future // future -> IO
io.to_future.await // IO -> future
fdo! Macro
Scala/Haskell-style do-notation. Works with any type that has and_then and map: Option, Result, Either, Validated, IO.
use fdo;
// Option
let result: = fdo! ;
// Result
let result: = fdo! ;
// Let bindings and guards
let result: = fdo! ;
Try
Captures panics as values, inspired by Scala's Try.
use *;
let result = try_catch;
assert!;
let result = try_catch;
assert!;
NonEmptyVec<T>
A Vec guaranteed to have at least one element at the type level.
use *;
use nev;
let v = nev!;
assert_eq!; // no Option — always exists
assert_eq!;
Persistent Collections
Immutable, structurally-shared collections backed by rpds. Thread-safe via Arc.
use *;
use ;
let l = list!;
let l2 = l.prepend;
assert_eq!; // original unchanged
assert_eq!;
let m = map!;
let m2 = m.insert;
assert_eq!; // original unchanged
assert_eq!;
Extension Traits
Adds Scala-style combinators to standard library types.
OptionExt: get_or_else, fold, to_either, to_validated, tap_some, tap_none, when, contains_where, zip_with
ResultExt: get_or_else, fold, to_either, to_validated, tap_ok, tap_err, bimap, recover, recover_with, swap
TupleExt: map_n for 2- through 5-tuples
Pure Trait
Lifts a value into any monadic context. Implemented for Option, Result, Either, Validated, and IO.
use *;
let opt: = pure; // Some(42)
let res: = pure; // Ok(42)
Usage
Add to your Cargo.toml:
[]
= { = "https://github.com/jordanburke/functype-rs" }
Or for specific crates:
[]
= { = "https://github.com/jordanburke/functype-rs" }
= { = "https://github.com/jordanburke/functype-rs" }
Requirements
- Rust 1.75+
- Edition 2021
License
MIT OR Apache-2.0