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