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