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