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}