fp_library/typeclasses/applicative.rs
1use crate::typeclasses::{Apply, ApplyFirst, ApplySecond, Functor, Pure};
2
3/// A typeclass for applicative functors.
4///
5/// `Applicative` extends `Functor` with the ability to lift values into a context
6/// (`pure`) and to apply functions within a context to values within a context
7/// (`apply`). It also provides additional operations for combining contexts
8/// (`apply_first`, `apply_second`).
9///
10/// Applicative functors are more powerful than functors but less powerful than
11/// monads. They allow for sequencing computations but with less flexibility
12/// than monads since the structure of the computation must be known in advance.
13///
14/// # Laws
15///
16/// Applicative instances must satisfy the following laws:
17/// * Identity: `apply(pure(identity))(v) = v`.
18/// * Composition: `apply(apply(apply(pure(compose))(u))(v))(w) = apply(u)(apply(v)(w))`.
19/// * Homomorphism: `apply(pure(f))(pure(x)) = pure(f(x))`.
20/// * Interchange: `apply(u)(pure(y)) = apply(pure(f => f(y)))(u)`.
21pub trait Applicative: Functor + Pure + Apply + ApplyFirst + ApplySecond {}
22
23/// Blanket implementation for the [`Applicative`] typeclass.
24///
25/// Any type that implements all the required supertraits automatically implements [`Applicative`].
26///
27/// The supertraits are:
28/// * [`Functor`]: for mapping functions over values in a context.
29/// * [`Pure`]: for lifting values into a context.
30/// * [`Apply`]: for applying functions in a context to values in a context.
31/// * [`ApplyFirst`]: for combining two contexts, keeping the first value.
32/// * [`ApplySecond`]: for combining two contexts, keeping the second value.
33impl<T> Applicative for T where T: Functor + Pure + Apply + ApplyFirst + ApplySecond {}
34
35#[cfg(test)]
36mod tests {
37 use crate::{
38 brands::OptionBrand,
39 typeclasses::Applicative,
40 types::{ResultWithErrBrand, ResultWithOkBrand, SoloBrand, VecBrand},
41 };
42
43 /// Asserts that a type implements [`Applicative`].
44 fn assert_applicative<T: Applicative>() {}
45
46 #[test]
47 /// Assert that brands implementing the required supertraits ([`Functor`],
48 /// [`Pure`], [`Apply`], [`ApplyFirst`], [`ApplySecond`]) also implement
49 /// [`Applicative`].
50 fn test_brands_implement_applicative() {
51 assert_applicative::<SoloBrand>();
52 assert_applicative::<OptionBrand>();
53 assert_applicative::<ResultWithErrBrand<()>>();
54 assert_applicative::<ResultWithOkBrand<()>>();
55 assert_applicative::<VecBrand>();
56 }
57}