Skip to main content

fp_library/classes/
send_ref_monad.rs

1//! Thread-safe by-ref monads, combining [`SendRefApplicative`](crate::classes::SendRefApplicative) and [`SendRefSemimonad`](crate::classes::SendRefSemimonad).
2//!
3//! This is the thread-safe counterpart of [`RefMonad`](crate::classes::RefMonad).
4
5#[fp_macros::document_module]
6mod inner {
7	use {
8		crate::classes::*,
9		fp_macros::*,
10	};
11
12	/// A type that supports thread-safe by-ref function application, pure value
13	/// injection, and monadic sequencing via references.
14	///
15	/// This is the thread-safe counterpart of [`RefMonad`].
16	/// Automatically implemented for any type implementing both
17	/// [`SendRefApplicative`] and [`SendRefSemimonad`].
18	///
19	/// A lawful `SendRefMonad` must satisfy the same three monad laws as
20	/// [`RefMonad`], with equality by evaluated value:
21	///
22	/// 1. **Left identity**: `send_ref_bind(send_ref_pure(&a), f)` evaluates
23	///    to the same value as `f(&a)`.
24	/// 2. **Right identity**: `send_ref_bind(m, |x| send_ref_pure(x))` evaluates
25	///    to the same value as `m`.
26	/// 3. **Associativity**: `send_ref_bind(send_ref_bind(m, f), g)` evaluates
27	///    to the same value as `send_ref_bind(m, |x| send_ref_bind(f(x), g))`.
28	#[document_examples]
29	///
30	/// ```
31	/// use fp_library::{
32	/// 	brands::*,
33	/// 	classes::*,
34	/// 	functions::*,
35	/// 	types::*,
36	/// };
37	///
38	/// let f = |x: &i32| {
39	/// 	let v = *x + 1;
40	/// 	ArcLazy::new(move || v)
41	/// };
42	/// let g = |x: &i32| {
43	/// 	let v = *x * 2;
44	/// 	ArcLazy::new(move || v)
45	/// };
46	///
47	/// // Left identity
48	/// let left = send_ref_bind::<LazyBrand<ArcLazyConfig>, _, _>(
49	/// 	&send_ref_pure::<LazyBrand<ArcLazyConfig>, _>(&5),
50	/// 	f,
51	/// );
52	/// assert_eq!(*left.evaluate(), *f(&5).evaluate());
53	///
54	/// // Right identity
55	/// let m = ArcLazy::new(|| 42);
56	/// let right = send_ref_bind::<LazyBrand<ArcLazyConfig>, _, _>(&m.clone(), |x: &i32| {
57	/// 	send_ref_pure::<LazyBrand<ArcLazyConfig>, _>(x)
58	/// });
59	/// assert_eq!(*right.evaluate(), *m.evaluate());
60	///
61	/// // Associativity
62	/// let m = ArcLazy::new(|| 3);
63	/// let lhs = send_ref_bind::<LazyBrand<ArcLazyConfig>, _, _>(
64	/// 	&send_ref_bind::<LazyBrand<ArcLazyConfig>, _, _>(&m.clone(), f),
65	/// 	g,
66	/// );
67	/// let rhs = send_ref_bind::<LazyBrand<ArcLazyConfig>, _, _>(&m, |x: &i32| {
68	/// 	send_ref_bind::<LazyBrand<ArcLazyConfig>, _, _>(&f(x), g)
69	/// });
70	/// assert_eq!(*lhs.evaluate(), *rhs.evaluate());
71	/// ```
72	pub trait SendRefMonad: SendRefApplicative + SendRefSemimonad {}
73
74	/// Blanket implementation of [`SendRefMonad`].
75	#[document_type_parameters("The brand type.")]
76	impl<Brand> SendRefMonad for Brand where Brand: SendRefApplicative + SendRefSemimonad {}
77}
78
79pub use inner::*;