fp_library/types/
arc_fn.rs

1//! Implementations for [atomically reference-counted][std::sync::Arc]
2//! [closures][Fn] (`Arc<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::sync::Arc;
10
11/// A brand type for [atomically reference-counted][std::sync::Arc]
12/// [closures][Fn] (`Arc<dyn Fn(A) -> B>`).
13///
14/// This struct implements [`ClonableFn`] to provide a way to construct and
15/// type-check [`Arc`]-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 ArcFnBrand;
20
21impl Kind1L2T for ArcFnBrand {
22	type Output<'a, A, B> = Arc<dyn 'a + Fn(A) -> B>;
23}
24
25impl ClonableFn for ArcFnBrand {
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		Arc::new(f)
30	}
31}
32
33impl Semigroupoid for ArcFnBrand {
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 ArcFnBrand {
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 Arc<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			ArcFnBrand::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 Arc<dyn 'b + Fn(A) -> B> {
70	fn empty() -> Self {
71		ArcFnBrand::new(move |_| B::empty())
72	}
73}