fp_library/typeclasses/apply.rs
1use crate::hkt::{Apply as App, Kind};
2
3/// A typeclass for types that support function application within a context.
4///
5/// `Apply` provides the ability to apply functions that are themselves
6/// wrapped in a context to values that are also wrapped in a context.
7/// This allows for sequencing computations where both the function and
8/// the value are in a context.
9///
10/// # Laws
11///
12/// Apply instances must satisfy the following law:
13/// * Composition: `apply(apply(f)(g))(x) = apply(f)(apply(g)(x))`.
14pub trait Apply {
15 /// Applies a function within a context to a value within a context.
16 ///
17 /// # Type Signature
18 ///
19 /// `forall f a b. Apply f => f (a -> b) -> f a -> f b`
20 ///
21 /// # Parameters
22 ///
23 /// * `ff`: A function wrapped in the context.
24 /// * `fa`: A value wrapped in the context.
25 ///
26 /// # Returns
27 ///
28 /// The result of applying the function to the value, all within the context.
29 fn apply<F, A, B>(ff: App<Self, (F,)>) -> impl Fn(App<Self, (A,)>) -> App<Self, (B,)>
30 where
31 Self: Kind<(F,)> + Kind<(A,)> + Kind<(B,)>,
32 App<Self, (F,)>: Clone,
33 F: Fn(A) -> B,
34 A: Clone;
35}
36
37/// Applies a function within a context to a value within a context.
38///
39/// Free function version that dispatches to [the typeclass method][`Apply::apply`].
40///
41/// # Type Signature
42///
43/// `forall f a b. Apply f => f (a -> b) -> f a -> f b`
44///
45/// # Parameters
46///
47/// * `ff`: A function wrapped in the context.
48/// * `fa`: A value wrapped in the context.
49///
50/// # Returns
51///
52/// The result of applying the function to the value, all within the context.
53///
54/// # Examples
55///
56/// ```
57/// use fp_library::{brands::OptionBrand, functions::apply};
58///
59/// assert_eq!(
60/// apply::<OptionBrand, _, _, _>(Some(|x: i32| x * 2))(Some(5)),
61/// Some(10)
62/// );
63/// ```
64pub fn apply<Brand, F, A, B>(ff: App<Brand, (F,)>) -> impl Fn(App<Brand, (A,)>) -> App<Brand, (B,)>
65where
66 Brand: Kind<(F,)> + Kind<(A,)> + Kind<(B,)> + Apply,
67 App<Brand, (F,)>: Clone,
68 F: Fn(A) -> B,
69 A: Clone,
70{
71 Brand::apply::<F, _, _>(ff)
72}