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 ///
25 /// # Returns
26 ///
27 /// A function that takes a value wrapped in the context and returns
28 /// the result of applying the function to the value, both 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/// # Examples
46///
47/// ```
48/// use fp_library::{brands::OptionBrand, functions::apply};
49///
50/// assert_eq!(
51/// apply::<OptionBrand, _, _, _>(Some(|x: i32| x * 2))(Some(5)),
52/// Some(10)
53/// );
54/// ```
55pub fn apply<Brand, F, A, B>(ff: App<Brand, (F,)>) -> impl Fn(App<Brand, (A,)>) -> App<Brand, (B,)>
56where
57 Brand: Kind<(F,)> + Kind<(A,)> + Kind<(B,)> + Apply,
58 App<Brand, (F,)>: Clone,
59 F: Fn(A) -> B,
60 A: Clone,
61{
62 move |fa| Brand::apply::<F, _, _>(ff.to_owned())(fa)
63}