22 releases (8 breaking)

0.8.3 Jun 15, 2023
0.7.0 Jun 12, 2023

#916 in Rust patterns

Download history 160/week @ 2024-02-14 194/week @ 2024-02-21 246/week @ 2024-02-28 435/week @ 2024-03-06 345/week @ 2024-03-13 219/week @ 2024-03-20 174/week @ 2024-03-27 172/week @ 2024-04-03 171/week @ 2024-04-10 117/week @ 2024-04-17 191/week @ 2024-04-24 222/week @ 2024-05-01 184/week @ 2024-05-08 212/week @ 2024-05-15 336/week @ 2024-05-22 210/week @ 2024-05-29

986 downloads per month

MIT/Apache

60KB
1.5K SLoC

Functors (and Monads) in Rust

This crate provides functors and monads in Rust. The API is designed to allow additional bounds on inner types, thus allowing implementation of a common Functor trait for all collections in std::collections, including those which have an Eq + Hash or an Ord bound on their relevant methods.

Also included in this crate are Functor and Monad implementations for boxed iterators, futures, and functions.


lib.rs:

Functors and monads in Rust

Note: This crate has some limitations. Be sure to read the "Caveats" section below.

Functors

The following traits are provided to describe functors:

  • Functor is a generic trait that provides an fmap method, which is a generalization of Option::map, Result::map, and so on, and which is implemented for a variety of types in the standard library.
  • FunctorSelf is a special case of Functor where types aren't changed when mapping. It is automatically implemented through a blanket implementation and it must be added as a bound when mapping a type to itself.
  • FunctorMut is a special case of FunctorSelf whose fmap_mut method operates on &mut self. It is not implemented automatically, but this crate provides implementations for all types in the standard library for which Functor is implemented.

Contravariant functors

The following traits are provided to describe contravariant functors, e.g. a Writer<B> that can be converted to a Writer<A> using an Fn(A) -> B.

Monads

The Monad trait describes functors which are also monads. Its supertrait Pure allows wrapping a single value. (Pure::pure is equivalent to what's usually called "return" in the context of monads). Nested monads implement NestedMonad through a blanket implementation.

Applicative functors

For applicative functors see the Applicative trait.

Caveats

From the trait definitions in this crate, Rust can't always deduce type equality or deduce the implemented traits automatically. This may result in complex (possibly viral) type bounds being required, which may strongly limit the usability of this crate. Consider the following examples:

fn foo1<'a, T>(functor: T) -> T
where
    T: Functor<'a, u16, Inner = u8>,
{
    functor.fmap(|x| x as u16).fmap(|x| x as u8) // works
}
fn foo2<'a, T>(functor: T)
where
    T: Functor<'a, u16, Inner = u8>,
    T: Functor<'a, u32, Inner = u16>,
{
    let _ = functor.fmap(|x| x as u16).fmap(|x| x as u32); // fails
}
fn foo3<'a, T>(functor: T)
where
    T: Functor<'a, u16, Inner = u8>,
    T::Mapped: Functor<'a, u32, Inner = u16>, // this is needed instead
{
    let _ = functor.fmap(|x| x as u16).fmap(|x| x as u32);
}

Also see FunctorSelf for a workaround in the most simple cases.

No runtime deps