fp_library/classes/semiapplicative.rs
1use crate::{
2 classes::{ClonableFn, clonable_fn::ApplyFn},
3 hkt::{Apply0L1T, Kind0L1T},
4};
5
6/// A type class for types that support function application within a context.
7///
8/// `Semiapplicative` 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/// `Semiapplicative` instances must satisfy the following law:
16/// * Composition: `apply(apply(f)(g))(x) = apply(f)(apply(g)(x))`.
17pub trait Semiapplicative: Kind0L1T {
18 /// Applies a function within a context to a value within a context.
19 ///
20 /// # Type Signature
21 ///
22 /// `forall a b. Semiapplicative 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, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: 'a>(
33 ff: Apply0L1T<Self, ApplyFn<'a, ClonableFnBrand, A, B>>
34 ) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<Self, B>>;
35}
36
37/// Applies a function within a context to a value within a context.
38///
39/// Free function version that dispatches to [the type class' associated function][`Semiapplicative::apply`].
40///
41/// # Type Signature
42///
43/// `forall a b. Semiapplicative 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, RcFnBrand}, functions::apply};
58/// use std::rc::Rc;
59///
60/// assert_eq!(
61/// apply::<RcFnBrand, OptionBrand, _, _>(Some(Rc::new(|x: i32| x * 2)))(Some(5)),
62/// Some(10)
63/// );
64/// ```
65pub fn apply<'a, ClonableFnBrand: 'a + ClonableFn, Brand: Semiapplicative, A: 'a + Clone, B: 'a>(
66 ff: Apply0L1T<Brand, ApplyFn<'a, ClonableFnBrand, A, B>>
67) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Brand, A>, Apply0L1T<Brand, B>> {
68 Brand::apply::<ClonableFnBrand, _, _>(ff)
69}