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