fp_library/classes/
semigroupoid.rs

1use crate::{
2	classes::{ClonableFn, clonable_fn::ApplyFn},
3	hkt::{Apply1L2T, Kind1L2T},
4};
5
6/// A type class for semigroupoids.
7///
8/// A `Semigroupoid` is a set of objects and composable relationships
9/// (morphisms) between them.
10///
11/// # Laws
12///
13/// Semigroupoid instances must satisfy the associative law:
14/// * Associativity: `compose(p)(compose(q)(r)) = compose(compose(p)(q))(r)`.
15///
16/// # Examples
17pub trait Semigroupoid: Kind1L2T {
18	/// Takes morphisms `f` and `g` and returns the morphism `f . g` (`f` composed with `g`).
19	///
20	/// # Type Signature
21	///
22	/// `forall b c d. Semigroupoid a => a c d -> a b c -> a b d`
23	///
24	/// # Parameters
25	///
26	/// * `f`: A morphism of type `a c d`.
27	/// * `g`: A morphism of type `a b c`.
28	///
29	/// # Returns
30	///
31	/// The morphism `f` composed with `g` of type `a b d`.
32	fn compose<'a, ClonableFnBrand: 'a + ClonableFn, B, C, D>(
33		f: Apply1L2T<'a, Self, C, D>
34	) -> ApplyFn<'a, ClonableFnBrand, Apply1L2T<'a, Self, B, C>, Apply1L2T<'a, Self, B, D>>;
35}
36
37/// Takes morphisms `f` and `g` and returns the morphism `f . g` (`f` composed with `g`).
38///
39/// Free function version that dispatches to [the type class' associated function][`Semigroupoid::compose`].
40///
41/// # Type Signature
42///
43/// `forall b c d. Semigroupoid a => a c d -> a b c -> a b d`
44///
45/// # Parameters
46///
47/// * `f`: A morphism of type `a c d`.
48/// * `g`: A morphism of type `a b c`.
49///
50/// # Returns
51///
52/// The morphism `f` composed with `g` of type `a b d`.
53///
54/// # Examples
55///
56/// ```
57/// use fp_library::{brands::RcFnBrand, functions::semigroupoid_compose};
58/// use std::rc::Rc;
59///
60/// let add_one = Rc::new(|x: i32| x + 1);
61/// let times_two = Rc::new(|x: i32| x * 2);
62/// let times_two_add_one = semigroupoid_compose::<RcFnBrand, RcFnBrand, _, _, _>(add_one)(times_two);
63///
64/// // 3 * 2 + 1 = 7
65/// assert_eq!(times_two_add_one(3), 7);
66/// ```
67pub fn semigroupoid_compose<'a, ClonableFnBrand: 'a + ClonableFn, Brand: Semigroupoid, B, C, D>(
68	f: Apply1L2T<'a, Brand, C, D>
69) -> ApplyFn<'a, ClonableFnBrand, Apply1L2T<'a, Brand, B, C>, Apply1L2T<'a, Brand, B, D>> {
70	Brand::compose::<'a, ClonableFnBrand, B, C, D>(f)
71}