fp_library/types/
rc_fn.rs

1//! Implementations for [reference-counted][std::rc::Rc] [closures][Fn]
2//! (`Rc<dyn Fn(A) -> B>`).
3
4use crate::{
5	classes::{Category, ClonableFn, Monoid, Semigroup, Semigroupoid, clonable_fn::ApplyFn},
6	functions::{compose, identity},
7	hkt::{Apply1L2T, Kind1L2T},
8};
9use std::rc::Rc;
10
11/// A brand type for [reference-counted][std::rc::Rc] [closures][Fn]
12/// (`Rc<dyn Fn(A) -> B>`).
13///
14/// This struct implements [`ClonableFn`] to provide a way to construct and
15/// type-check [`Rc`]-wrapped closures in a generic context. The lifetime `'a`
16/// ensures the closure doesn't outlive referenced data, while `A` and `B`
17/// represent input and output types.
18#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct RcFnBrand;
20
21impl Kind1L2T for RcFnBrand {
22	type Output<'a, A, B> = Rc<dyn 'a + Fn(A) -> B>;
23}
24
25impl ClonableFn for RcFnBrand {
26	type Output<'a, A: 'a, B: 'a> = Apply1L2T<'a, Self, A, B>;
27
28	fn new<'a, A: 'a, B: 'a>(f: impl 'a + Fn(A) -> B) -> ApplyFn<'a, Self, A, B> {
29		Rc::new(f)
30	}
31}
32
33impl Semigroupoid for RcFnBrand {
34	fn compose<'a, ClonableFnBrand: 'a + ClonableFn, B, C, D>(
35		f: Apply1L2T<'a, Self, C, D>
36	) -> ApplyFn<'a, ClonableFnBrand, Apply1L2T<'a, Self, B, C>, Apply1L2T<'a, Self, B, D>> {
37		ClonableFnBrand::new::<'a, _, _>(move |g: Apply1L2T<'a, Self, B, C>| {
38			Self::new::<'a, _, _>({
39				let f = f.clone();
40				move |a| compose::<'a, Self, _, _, _>(f.clone())(g.clone())(a)
41			})
42		})
43	}
44}
45
46impl Category for RcFnBrand {
47	fn identity<'a, A: 'a>() -> Apply1L2T<'a, Self, A, A> {
48		Self::new::<'a, _, _>(identity)
49	}
50}
51
52impl<'b, A: 'b + Clone, B: Semigroup<'b> + 'b> Semigroup<'b> for Rc<dyn 'b + Fn(A) -> B> {
53	fn append<'a, ClonableFnBrand: 'a + 'b + ClonableFn>(
54		a: Self
55	) -> ApplyFn<'a, ClonableFnBrand, Self, Self>
56	where
57		Self: Sized,
58		'b: 'a,
59	{
60		ClonableFnBrand::new(move |b: Self| {
61			RcFnBrand::new({
62				let a = a.clone();
63				move |c: A| B::append::<ClonableFnBrand>(a(c.clone()))(b(c))
64			})
65		})
66	}
67}
68
69impl<'b, A: 'b + Clone, B: Monoid<'b> + 'b> Monoid<'b> for Rc<dyn 'b + Fn(A) -> B> {
70	fn empty() -> Self {
71		RcFnBrand::new(move |_| B::empty())
72	}
73}