Skip to main content

fp_library/types/optics/
grating.rs

1//! The `Grating` profunctor, used for grates.
2//!
3//! `Grating<A, B, S, T>` wraps a function `((S -> A) -> B) -> T`.
4
5#[fp_macros::document_module]
6mod inner {
7	use {
8		crate::{
9			Apply,
10			brands::optics::*,
11			classes::{
12				profunctor::{
13					Closed,
14					Profunctor,
15				},
16				*,
17			},
18			impl_kind,
19			kinds::*,
20		},
21		fp_macros::*,
22	};
23
24	/// The `Grating` profunctor.
25	#[document_type_parameters(
26		"The lifetime of the functions.",
27		"The cloneable function brand.",
28		"The type of the value produced by the inner function.",
29		"The type of the value consumed by the inner function.",
30		"The source type of the structure.",
31		"The target type of the structure."
32	)]
33	pub struct Grating<'a, FunctionBrand: LiftFn, A: 'a, B: 'a, S: 'a, T: 'a> {
34		/// Grating function.
35		pub run: <FunctionBrand as CloneFn>::Of<
36			'a,
37			<FunctionBrand as CloneFn>::Of<'a, <FunctionBrand as CloneFn>::Of<'a, S, A>, B>,
38			T,
39		>,
40	}
41
42	#[document_type_parameters(
43		"The lifetime of the functions.",
44		"The cloneable function brand.",
45		"The type of the value produced by the inner function.",
46		"The type of the value consumed by the inner function.",
47		"The source type of the structure.",
48		"The target type of the structure."
49	)]
50	impl<'a, FunctionBrand: LiftFn, A: 'a, B: 'a, S: 'a, T: 'a> Grating<'a, FunctionBrand, A, B, S, T> {
51		/// Creates a new `Grating` instance.
52		#[document_signature]
53		///
54		#[document_parameters("The grating function.")]
55		///
56		#[document_returns("A new instance of the type.")]
57		///
58		#[document_examples]
59		///
60		/// ```
61		/// use fp_library::{
62		/// 	brands::*,
63		/// 	functions::*,
64		/// 	types::optics::Grating,
65		/// };
66		///
67		/// let grating =
68		/// 	Grating::<RcFnBrand, i32, i32, (i32, i32), i32>::new(lift_fn_new::<RcFnBrand, _, _>(
69		/// 		|f: std::rc::Rc<dyn Fn(std::rc::Rc<dyn Fn((i32, i32)) -> i32>) -> i32>| {
70		/// 			let get_x = lift_fn_new::<RcFnBrand, _, _>(|(x, _)| x);
71		/// 			let get_y = lift_fn_new::<RcFnBrand, _, _>(|(_, y)| y);
72		/// 			f(get_x) + f(get_y)
73		/// 		},
74		/// 	));
75		/// let result = (grating.run)(lift_fn_new::<RcFnBrand, _, _>(
76		/// 	|g: std::rc::Rc<dyn Fn((i32, i32)) -> i32>| g((10, 20)),
77		/// ));
78		/// assert_eq!(result, 30);
79		/// ```
80		pub fn new(
81			run: <FunctionBrand as CloneFn>::Of<
82				'a,
83				<FunctionBrand as CloneFn>::Of<'a, <FunctionBrand as CloneFn>::Of<'a, S, A>, B>,
84				T,
85			>
86		) -> Self {
87			Grating {
88				run,
89			}
90		}
91	}
92
93	impl_kind! {
94		impl<FunctionBrand: LiftFn + 'static, A: 'static, B: 'static> for GratingBrand<FunctionBrand, A, B> {
95			#[document_default]
96			type Of<'a, S: 'a, T: 'a>: 'a = Grating<'a, FunctionBrand, A, B, S, T>;
97		}
98	}
99
100	#[document_type_parameters(
101		"The cloneable function brand.",
102		"The type of the value produced by the inner function.",
103		"The type of the value consumed by the inner function."
104	)]
105	impl<FunctionBrand: LiftFn + 'static, A: 'static, B: 'static> Profunctor
106		for GratingBrand<FunctionBrand, A, B>
107	{
108		/// Maps functions over the input and output of the `Grating` profunctor.
109		#[document_signature]
110		///
111		#[document_type_parameters(
112			"The lifetime of the functions.",
113			"The source type of the new structure.",
114			"The target type of the new structure.",
115			"The source type of the original structure.",
116			"The target type of the original structure."
117		)]
118		///
119		#[document_parameters(
120			"The function to apply to the input.",
121			"The function to apply to the output.",
122			"The grating instance to transform."
123		)]
124		///
125		#[document_returns("A transformed `Grating` instance.")]
126		///
127		#[document_examples]
128		///
129		/// ```
130		/// use fp_library::{
131		/// 	brands::{
132		/// 		optics::*,
133		/// 		*,
134		/// 	},
135		/// 	classes::{
136		/// 		clone_fn::new as lift_fn_new,
137		/// 		optics::*,
138		/// 		profunctor::*,
139		/// 	},
140		/// 	types::optics::*,
141		/// };
142		///
143		/// // Grating is usually used internally by Grate optics
144		/// let grating =
145		/// 	Grating::<RcFnBrand, i32, i32, (i32, i32), i32>::new(lift_fn_new::<RcFnBrand, _, _>(
146		/// 		|f: std::rc::Rc<dyn Fn(std::rc::Rc<dyn Fn((i32, i32)) -> i32>) -> i32>| {
147		/// 			let get_x = lift_fn_new::<RcFnBrand, _, _>(|(x, _)| x);
148		/// 			let get_y = lift_fn_new::<RcFnBrand, _, _>(|(_, y)| y);
149		/// 			f(get_x) + f(get_y)
150		/// 		},
151		/// 	));
152		/// let transformed = <GratingBrand<RcFnBrand, i32, i32> as Profunctor>::dimap(
153		/// 	|s: (i32, i32)| s,
154		/// 	|t: i32| t,
155		/// 	grating,
156		/// );
157		/// let result = (transformed.run)(lift_fn_new::<RcFnBrand, _, _>(
158		/// 	|g: std::rc::Rc<dyn Fn((i32, i32)) -> i32>| g((10, 20)),
159		/// ));
160		/// assert_eq!(result, 30);
161		/// ```
162		fn dimap<'a, S: 'a, T: 'a, U: 'a, V: 'a>(
163			st: impl Fn(S) -> T + 'a,
164			uv: impl Fn(U) -> V + 'a,
165			puv: Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, T, U>),
166		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, S, V>) {
167			let run = puv.run;
168			let st = <FunctionBrand as LiftFn>::new(st);
169			let uv = <FunctionBrand as LiftFn>::new(uv);
170			Grating::<FunctionBrand, A, B, S, V>::new(<FunctionBrand as LiftFn>::new(
171				move |f: <FunctionBrand as CloneFn>::Of<
172					'a,
173					<FunctionBrand as CloneFn>::Of<'a, S, A>,
174					B,
175				>| {
176					let st = st.clone();
177					let uv = uv.clone();
178					(*uv)((*run)(<FunctionBrand as LiftFn>::new(
179						move |g: <FunctionBrand as CloneFn>::Of<'a, T, A>| {
180							let st = st.clone();
181							f(<FunctionBrand as LiftFn>::new(move |s| g((*st)(s))))
182						},
183					)))
184				},
185			))
186		}
187	}
188
189	#[document_type_parameters(
190		"The cloneable function brand.",
191		"The type of the value produced by the inner function.",
192		"The type of the value consumed by the inner function."
193	)]
194	impl<FunctionBrand: LiftFn + 'static, A: 'static, B: 'static> Closed<FunctionBrand>
195		for GratingBrand<FunctionBrand, A, B>
196	{
197		/// Lifts the `Grating` profunctor to operate on functions.
198		#[document_signature]
199		///
200		#[document_type_parameters(
201			"The lifetime of the functions.",
202			"The source type of the structure.",
203			"The target type of the structure.",
204			"The type of the function input."
205		)]
206		///
207		#[document_parameters("The grating instance to transform.")]
208		///
209		#[document_returns("A transformed `Grating` instance that operates on functions.")]
210		///
211		#[document_examples]
212		///
213		/// ```
214		/// use fp_library::{
215		/// 	brands::{
216		/// 		optics::*,
217		/// 		*,
218		/// 	},
219		/// 	classes::{
220		/// 		optics::*,
221		/// 		profunctor::*,
222		/// 		*,
223		/// 	},
224		/// 	functions::*,
225		/// 	types::optics::*,
226		/// };
227		///
228		/// let grating =
229		/// 	Grating::<RcFnBrand, i32, i32, (i32, i32), i32>::new(lift_fn_new::<RcFnBrand, _, _>(
230		/// 		|f: std::rc::Rc<dyn Fn(std::rc::Rc<dyn Fn((i32, i32)) -> i32>) -> i32>| {
231		/// 			let get_x = lift_fn_new::<RcFnBrand, _, _>(|(x, _)| x);
232		/// 			let get_y = lift_fn_new::<RcFnBrand, _, _>(|(_, y)| y);
233		/// 			f(get_x) + f(get_y)
234		/// 		},
235		/// 	));
236		///
237		/// let closed_grating = <GratingBrand<RcFnBrand, i32, i32> as Closed<RcFnBrand>>::closed::<
238		/// 	(i32, i32),
239		/// 	i32,
240		/// 	String,
241		/// >(grating);
242		///
243		/// let run_closed = closed_grating.run;
244		/// type GetterFn = std::rc::Rc<dyn Fn(std::rc::Rc<dyn Fn(String) -> (i32, i32)>) -> i32>;
245		/// let result_fn = run_closed(lift_fn_new::<RcFnBrand, _, _>(|getter: GetterFn| {
246		/// 	// getter: (String -> (i32, i32)) -> i32
247		/// 	// We provide a function that produces a pair from a string
248		/// 	getter(lift_fn_new::<RcFnBrand, _, _>(|s: String| (s.len() as i32, 10)))
249		/// }));
250		///
251		/// assert_eq!(result_fn("hello".to_string()), 5 + 10);
252		/// ```
253		fn closed<'a, S: 'a, T: 'a, X: 'a + Clone>(
254			pab: Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, S, T>)
255		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a, U: 'a>: 'a; )>::Of<'a, <FunctionBrand as CloneFn>::Of<'a, X, S>, <FunctionBrand as CloneFn>::Of<'a, X, T>>)
256		{
257			let run = pab.run;
258			Grating::<
259				FunctionBrand,
260				A,
261				B,
262				<FunctionBrand as CloneFn>::Of<'a, X, S>,
263				<FunctionBrand as CloneFn>::Of<'a, X, T>,
264			>::new(<FunctionBrand as LiftFn>::new(
265				move |g: <FunctionBrand as CloneFn>::Of<
266					'a,
267					<FunctionBrand as CloneFn>::Of<'a, <FunctionBrand as CloneFn>::Of<'a, X, S>, A>,
268					B,
269				>| {
270					let run = run.clone();
271					<FunctionBrand as LiftFn>::new(move |x: X| {
272						let g = g.clone();
273						let x = x.clone();
274						(*run)(<FunctionBrand as LiftFn>::new(
275							move |h: <FunctionBrand as CloneFn>::Of<'a, S, A>| {
276								let x = x.clone();
277								g(<FunctionBrand as LiftFn>::new(
278									move |k: <FunctionBrand as CloneFn>::Of<'a, X, S>| {
279										h(k(x.clone()))
280									},
281								))
282							},
283						))
284					})
285				},
286			))
287		}
288	}
289}
290pub use inner::*;