fp_library/classes/semimonad.rs
1//! Semimonad type class.
2//!
3//! This module defines the [`Semimonad`] trait, which allows for sequencing computations where the second computation depends on the result of the first.
4
5use crate::{Apply, kinds::*};
6
7/// Sequences two computations, allowing the second to depend on the value computed by the first.
8///
9/// If `x` has type `m a` and `f` has type `a -> m b`, then `bind(x, f)` has type `m b`,
10/// representing the result of executing `x` to get a value of type `a` and then
11/// passing it to `f` to get a computation of type `m b`.
12pub trait Semimonad: Kind_cdc7cd43dac7585f {
13 /// Sequences two computations, allowing the second to depend on the value computed by the first.
14 ///
15 /// This method chains two computations, where the second computation depends on the result of the first.
16 ///
17 /// ### Type Signature
18 ///
19 /// `forall a b. Semimonad m => (m a, a -> m b) -> m b`
20 ///
21 /// ### Type Parameters
22 ///
23 /// * `F`: The type of the function to apply.
24 /// * `A`: The type of the result of the first computation.
25 /// * `B`: The type of the result of the second computation.
26 ///
27 /// ### Parameters
28 ///
29 /// * `ma`: The first computation.
30 /// * `f`: The function to apply to the result of the first computation.
31 ///
32 /// ### Returns
33 ///
34 /// The result of the second computation.
35 ///
36 /// ### Examples
37 ///
38 /// ```
39 /// use fp_library::classes::semimonad::Semimonad;
40 /// use fp_library::brands::OptionBrand;
41 ///
42 /// let x = Some(5);
43 /// let y = OptionBrand::bind(x, |i| Some(i * 2));
44 /// assert_eq!(y, Some(10));
45 /// ```
46 fn bind<'a, F, A: 'a, B: 'a>(
47 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
48 f: F,
49 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
50 where
51 F: Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a;
52}
53
54/// Sequences two computations, allowing the second to depend on the value computed by the first.
55///
56/// Free function version that dispatches to [the type class' associated function][`Semimonad::bind`].
57///
58/// ### Type Signature
59///
60/// `forall a b. Semimonad m => (m a, a -> m b) -> m b`
61///
62/// ### Type Parameters
63///
64/// * `Brand`: The brand of the semimonad.
65/// * `F`: The type of the function to apply.
66/// * `A`: The type of the result of the first computation.
67/// * `B`: The type of the result of the second computation.
68///
69/// ### Parameters
70///
71/// * `ma`: The first computation.
72/// * `f`: The function to apply to the result of the first computation.
73///
74/// ### Returns
75///
76/// The result of the second computation.
77///
78/// ### Examples
79///
80/// ```
81/// use fp_library::classes::semimonad::bind;
82/// use fp_library::brands::OptionBrand;
83///
84/// let x = Some(5);
85/// let y = bind::<OptionBrand, _, _, _>(x, |i| Some(i * 2));
86/// assert_eq!(y, Some(10));
87/// ```
88pub fn bind<'a, Brand: Semimonad, F, A: 'a, B: 'a>(
89 ma: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
90 f: F,
91) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
92where
93 F: Fn(A) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
94{
95 Brand::bind(ma, f)
96}