fp_library/typeclasses/
apply.rs

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