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_c3c3610c70409ee6 {
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!(
48 brand: Self,
49 signature: ('a, A: 'a) -> 'a,
50 ),
51 f: F,
52 ) -> Apply!(
53 brand: Self,
54 signature: ('a, B: 'a) -> 'a,
55 )
56 where
57 F: Fn(
58 A,
59 ) -> Apply!(
60 brand: Self,
61 signature: ('a, B: 'a) -> 'a,
62 ) + 'a;
63}
64
65/// Sequences two computations, allowing the second to depend on the value computed by the first.
66///
67/// Free function version that dispatches to [the type class' associated function][`Semimonad::bind`].
68///
69/// ### Type Signature
70///
71/// `forall a b. Semimonad m => (m a, a -> m b) -> m b`
72///
73/// ### Type Parameters
74///
75/// * `Brand`: The brand of the semimonad.
76/// * `F`: The type of the function to apply.
77/// * `A`: The type of the result of the first computation.
78/// * `B`: The type of the result of the second computation.
79///
80/// ### Parameters
81///
82/// * `ma`: The first computation.
83/// * `f`: The function to apply to the result of the first computation.
84///
85/// ### Returns
86///
87/// The result of the second computation.
88///
89/// ### Examples
90///
91/// ```
92/// use fp_library::classes::semimonad::bind;
93/// use fp_library::brands::OptionBrand;
94///
95/// let x = Some(5);
96/// let y = bind::<OptionBrand, _, _, _>(x, |i| Some(i * 2));
97/// assert_eq!(y, Some(10));
98/// ```
99pub fn bind<'a, Brand: Semimonad, F, A: 'a, B: 'a>(
100 ma: Apply!(
101 brand: Brand,
102 signature: ('a, A: 'a) -> 'a,
103 ),
104 f: F,
105) -> Apply!(
106 brand: Brand,
107 signature: ('a, B: 'a) -> 'a,
108)
109where
110 F: Fn(
111 A,
112 ) -> Apply!(
113 brand: Brand,
114 signature: ('a, B: 'a) -> 'a,
115 ) + 'a,
116{
117 Brand::bind(ma, f)
118}