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}