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}