rust2fun (pronounced: rʌstafʌn)

Crates.io docs.rs build

A library for functional programming in Rust.

Build

By default, the library is built with the std feature enabled. To disable it, use the --no-default-features flag.

Usage

Add this to your Cargo.toml:

toml [dependencies] rust2fun = "0.2.0"

and import the prelude:

rust use rust2fun::prelude::*;

Supported features

Combinators:

Type classes:

Data types:

Examples

  1. Function print_user_credit_card accepts user(s) wrapped in any effect (Option, Result, Vec, etc.) and prints corresponding credit card(s).

```rust fn getcreditcard(user: User) -> CreditCard { // Get credit card for user }

fn printcreditcard(card: CreditCard) { // Print credit card details }

fn printcreditcardof(user: F) where F: Functor, F::Target: Functor<(), Param=CreditCard>, { user.map(getcreditcard).map(printcredit_card); } ```

...usage:

```rust fn user(id: u32) -> Option { // Get user from database }

fn all_users() -> Vec { // Get all users from database }

printcreditcardof(user(1)); printcreditcardof(all_users()); ```

  1. Validation accumulating all errors.

Assuming we have the following validation rules that need to be applied to create a new credit card:

```rust fn validate_number(number: CreditCardNumber) -> Result { // Validating credit card number }

fn validate_expiration(date: Date) -> Result { // Validating expiration date }

fn validate_cvv(cvv: Code) -> Result { // Validating CVV code } ```

...we can create a new credit card by applying all validation rules and collecting all errors in a vector Vec, non-empty vector NEVec (like in the example) or other semigroup (e.g. String, u32, etc.):

rust fn validate_credit_card( number: CreditCardNumber, expiration: Date, cvv: Code, ) -> ValidatedNev<CreditCard, Error> { ValidatedNev::pure(CreditCard::new) .ap3(validate_number(number).into(), validate_expiration(expiration).into(), validate_cvv(cvv).into()) }

...alternatively, this can be done using the map3 method:

```rust fn validatecreditcard( number: CreditCardNumber, expiration: Date, cvv: Code, ) -> ValidatedNev { let number: ValidatedNev<_, _> = validatenumber(number).into(); let expiration = validateexpiration(expiration).into(); let cvv = validate_cvv(cvv).into();

Apply::map3(number, expiration, cvv, CreditCard::new)

} ```

  1. bind! notation for monads (like do notation in Haskell or for comprehension in Scala):

Assuming we have the following functions defined:

```rust fn getopeningprices() -> Vec<(AssetId, i32)> { // Get opening prices from an external service }

fn getclosingprices() -> Vec<(AssetId, i32)> { // Get closing prices from an external service }

fn getassetname(id: AssetId) -> Option { // Recover asset name for the given id } ```

...we can use bind! notation to calculate daily profit for each asset:

rust let profits: Vec<(String, i32)> = bind! { for (id_open, opening_price) in get_opening_prices(); for (id_close, closing_price) in get_closing_prices(); let diff = closing_price - opening_price; for name in get_asset_name(id_open).into_iter().collect::<Vec<_>>(), if id_open == id_close && diff > 0; (name, diff) };

Release notes

0.1.0 (2023-01-22)

0.2.0 (2023-09-10)