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}