fp_library/classes/
semimonad.rs

1use crate::{
2	classes::{ClonableFn, clonable_fn::ApplyFn},
3	hkt::{Apply0L1T, Kind0L1T},
4};
5
6/// Sequences two computations, allowing the second to depend on the value computed by the first.
7///
8/// If `x` has type `m a` and `f` has type `a -> m b`, then `bind(x)(f)` has type `m b`,
9/// representing the result of executing `x` to get a value of type `a` and then
10/// passing it to `f` to get a computation of type `m b`.
11pub trait Semimonad: Kind0L1T {
12	/// Sequences two computations, allowing the second to depend on the value computed by the first.
13	///
14	/// # Type Signature
15	///
16	/// `forall a b. Semimonad m => m a -> (a -> m b) -> m b`
17	///
18	/// # Parameters
19	///
20	/// * `ma`: The first computation in the context.
21	/// * `f`: A function that takes the result of the first computation and returns the second computation in the context.
22	///
23	/// # Returns
24	///
25	/// A computation that sequences the two operations.
26	fn bind<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: Clone>(
27		ma: Apply0L1T<Self, A>
28	) -> ApplyFn<
29		'a,
30		ClonableFnBrand,
31		ApplyFn<'a, ClonableFnBrand, A, Apply0L1T<Self, B>>,
32		Apply0L1T<Self, B>,
33	>;
34}
35
36/// Sequences two computations, allowing the second to depend on the value computed by the first.
37///
38/// Free function version that dispatches to [the type class' associated function][`Semimonad::bind`].
39///
40/// # Type Signature
41///
42/// `forall a b. Semimonad m => m a -> (a -> m b) -> m b`
43///
44/// # Parameters
45///
46/// * `ma`: The first computation in the context.
47/// * `f`: A function that takes the result of the first computation and returns the second computation in the context.
48///
49/// # Returns
50///
51/// A computation that sequences the two operations.
52///
53/// # Examples
54///
55/// ```
56/// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::{bind, pure}};
57/// use std::rc::Rc;
58///
59/// assert_eq!(bind::<RcFnBrand, OptionBrand, _, _>(Some(5))(Rc::new(|x| Some(x * 2))), Some(10));
60/// ```
61pub fn bind<'a, ClonableFnBrand: 'a + ClonableFn, Brand: Semimonad, A: 'a + Clone, B: Clone>(
62	ma: Apply0L1T<Brand, A>
63) -> ApplyFn<
64	'a,
65	ClonableFnBrand,
66	ApplyFn<'a, ClonableFnBrand, A, Apply0L1T<Brand, B>>,
67	Apply0L1T<Brand, B>,
68> {
69	Brand::bind::<ClonableFnBrand, A, B>(ma)
70}