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}