fp_library/classes/semimonad.rs
1use crate::{
2 classes::{ClonableFn, clonable_fn::ApplyFn},
3 hkt::{Apply0L1T, Kind0L1T},
4};
5
6/// Sequences two computations, allowing the second to depend on the value computed by the first.
7///
8/// If `x` has type `m a` and `f` has type `a -> m b`, then `bind(x)(f)` has type `m b`,
9/// representing the result of executing `x` to get a value of type `a` and then
10/// passing it to `f` to get a computation of type `m b`.
11pub trait Semimonad: Kind0L1T {
12 /// Sequences two computations, allowing the second to depend on the value computed by the first.
13 ///
14 /// # Type Signature
15 ///
16 /// `forall a b. Semimonad m => m a -> (a -> m b) -> m b`
17 ///
18 /// # Parameters
19 ///
20 /// * `ma`: The first computation in the context.
21 /// * `f`: A function that takes the result of the first computation and returns the second computation in the context.
22 ///
23 /// # Returns
24 ///
25 /// A computation that sequences the two operations.
26 fn bind<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: Clone>(
27 ma: Apply0L1T<Self, A>
28 ) -> ApplyFn<
29 'a,
30 ClonableFnBrand,
31 ApplyFn<'a, ClonableFnBrand, A, Apply0L1T<Self, B>>,
32 Apply0L1T<Self, B>,
33 >;
34}
35
36/// Sequences two computations, allowing the second to depend on the value computed by the first.
37///
38/// Free function version that dispatches to [the type class' associated function][`Semimonad::bind`].
39///
40/// # Type Signature
41///
42/// `forall a b. Semimonad m => m a -> (a -> m b) -> m b`
43///
44/// # Parameters
45///
46/// * `ma`: The first computation in the context.
47/// * `f`: A function that takes the result of the first computation and returns the second computation in the context.
48///
49/// # Returns
50///
51/// A computation that sequences the two operations.
52///
53/// # Examples
54///
55/// ```
56/// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::{bind, pure}};
57/// use std::rc::Rc;
58///
59/// assert_eq!(bind::<RcFnBrand, OptionBrand, _, _>(Some(5))(Rc::new(|x| Some(x * 2))), Some(10));
60/// ```
61pub fn bind<'a, ClonableFnBrand: 'a + ClonableFn, Brand: Semimonad, A: 'a + Clone, B: Clone>(
62 ma: Apply0L1T<Brand, A>
63) -> ApplyFn<
64 'a,
65 ClonableFnBrand,
66 ApplyFn<'a, ClonableFnBrand, A, Apply0L1T<Brand, B>>,
67 Apply0L1T<Brand, B>,
68> {
69 Brand::bind::<ClonableFnBrand, A, B>(ma)
70}