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::*;