Skip to main content

fp_library/classes/
ref_semiapplicative.rs

1//! Applying wrapped by-ref functions within contexts with [`ref_apply`].
2//!
3//! Like [`Semiapplicative::apply`](crate::classes::Semiapplicative::apply), but the
4//! wrapped functions receive `&A` instead of owned values. Uses
5//! [`CloneFn<Ref>`](crate::classes::CloneFn) for the function wrappers.
6//!
7//! ### Examples
8//!
9//! ```
10//! use fp_library::{
11//! 	brands::*,
12//! 	classes::*,
13//! 	functions::*,
14//! 	types::*,
15//! };
16//!
17//! let f = RcLazy::pure(std::rc::Rc::new(|x: &i32| *x * 2) as std::rc::Rc<dyn Fn(&i32) -> i32>);
18//! let x = RcLazy::pure(5);
19//! let result = ref_apply::<RcFnBrand, LazyBrand<RcLazyConfig>, _, _>(&f, &x);
20//! assert_eq!(*result.evaluate(), 10);
21//! ```
22
23#[fp_macros::document_module]
24mod inner {
25	use {
26		crate::{
27			classes::*,
28			dispatch::Ref,
29			kinds::*,
30		},
31		fp_macros::*,
32	};
33
34	/// A type class for applying wrapped by-ref functions within contexts.
35	///
36	/// The wrapped functions have type `Fn(&A) -> B` (via [`CloneFn<Ref>`]),
37	/// so no `Clone` bound on `A` is needed. The function receives a reference
38	/// and produces an owned result.
39	#[kind(type Of<'a, A: 'a>: 'a;)]
40	pub trait RefSemiapplicative: RefLift + RefFunctor {
41		/// Applies a wrapped by-ref function within a context to a value within a context.
42		#[document_signature]
43		///
44		#[document_type_parameters(
45			"The lifetime of the values.",
46			"The brand of the cloneable function wrapper.",
47			"The type of the input value.",
48			"The type of the output value."
49		)]
50		///
51		#[document_parameters(
52			"The context containing the wrapped by-ref function(s).",
53			"The context containing the value(s)."
54		)]
55		///
56		#[document_returns(
57			"A new context containing the result(s) of applying the function(s) to the value(s)."
58		)]
59		#[document_examples]
60		///
61		/// ```
62		/// use fp_library::{
63		/// 	brands::*,
64		/// 	classes::*,
65		/// 	functions::*,
66		/// 	types::*,
67		/// };
68		///
69		/// let f = RcLazy::pure(std::rc::Rc::new(|x: &i32| *x * 2) as std::rc::Rc<dyn Fn(&i32) -> i32>);
70		/// let x = RcLazy::pure(5);
71		/// let result = LazyBrand::<RcLazyConfig>::ref_apply::<RcFnBrand, _, _>(&f, &x);
72		/// assert_eq!(*result.evaluate(), 10);
73		/// ```
74		fn ref_apply<'a, FnBrand: 'a + CloneFn<Ref>, A: 'a, B: 'a>(
75			ff: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneFn<Ref>>::Of<'a, A, B>>),
76			fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
77		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>);
78	}
79
80	/// Applies a wrapped by-ref function within a context to a value within a context.
81	///
82	/// Free function version that dispatches to [the type class' associated function][`RefSemiapplicative::ref_apply`].
83	#[document_signature]
84	///
85	#[document_type_parameters(
86		"The lifetime of the values.",
87		"The brand of the cloneable function wrapper.",
88		"The brand of the context.",
89		"The type of the input value.",
90		"The type of the output value."
91	)]
92	///
93	#[document_parameters(
94		"The context containing the wrapped by-ref function(s).",
95		"The context containing the value(s)."
96	)]
97	///
98	#[document_returns(
99		"A new context containing the result(s) of applying the function(s) to the value(s)."
100	)]
101	#[document_examples]
102	///
103	/// ```
104	/// use fp_library::{
105	/// 	brands::*,
106	/// 	classes::*,
107	/// 	functions::*,
108	/// 	types::*,
109	/// };
110	///
111	/// let f = RcLazy::pure(std::rc::Rc::new(|x: &i32| *x * 2) as std::rc::Rc<dyn Fn(&i32) -> i32>);
112	/// let x = RcLazy::pure(5);
113	/// let result = ref_apply::<RcFnBrand, LazyBrand<RcLazyConfig>, _, _>(&f, &x);
114	/// assert_eq!(*result.evaluate(), 10);
115	/// ```
116	pub fn ref_apply<'a, FnBrand: 'a + CloneFn<Ref>, Brand: RefSemiapplicative, A: 'a, B: 'a>(
117		ff: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneFn<Ref>>::Of<'a, A, B>>),
118		fa: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
119	) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
120		Brand::ref_apply::<FnBrand, A, B>(ff, fa)
121	}
122}
123
124pub use inner::*;