1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use crate::prelude::*;
/// [`Functor`], but specialized to know at compile-time
/// that the mapping function will only be called one time.
pub trait FunctorOnce<F, A>
where F: HKT1<T<A> = Self>
{
/// See [`FunctorOnce`]
fn fmap1<AB, B>(self, f: AB) -> F::T<B>
where AB: F1Once<A, Ret = B>;
}
/// Functor adds a mapping operation to generic types.
///
/// In essence, `map` allows one to lift a function of type
/// `fn(A) -> B` to some new Functor context, e.g. `fn(Option<A>) -> Option<B>`.
///
/// # Laws
/// - Invoking map with an identity function (e.g. `|a| a`) should do absolutely nothing.
///
/// ```
/// use naan::prelude::*;
///
/// #[derive(Debug, PartialEq, Eq)]
/// struct Container<T>(T);
/// struct ContainerHKT;
/// impl HKT1 for ContainerHKT {
/// type T<A> = Container<A>;
/// }
///
/// impl<A> Functor<ContainerHKT, A> for Container<A> {
/// fn fmap<AB, B>(self, f: AB) -> Container<B>
/// where AB: F1<A, Ret = B>
/// {
/// Container(f.call(self.0))
/// }
/// }
///
/// assert_eq!(Container(0u8).fmap(|n| n + 1).fmap(|n: u8| n.to_string()),
/// Container("1".to_string()))
/// ```
pub trait Functor<F, A>
where F: HKT1<T<A> = Self>
{
/// Use a function from `A -> B` to transform an
/// `F<A>` to an `F<B>`.
fn fmap<AB, B>(self, f: AB) -> F::T<B>
where AB: F1<A, Ret = B>;
}
/// [`Functor`] but with looser type constraints,
/// allowing for blanket [`Functor`] implementations
/// on types [`Equiv`]alent to `F<A>`
pub trait FunctorSurrogate<F, A>
where F: HKT1,
Self: Equiv<To = F::T<A>>
{
/// Type yielded by `fmap` that is akin to `F::T<B>`.
///
/// The output type may use both type parameters, or only one.
///
/// The reason we allow the output to be parameterized by `AB` (the function from `A -> B`)
/// is so that the returning type can store **the function** and defer transformation.
///
/// This allows implementing lazy functors with no heap dependency (ex. [`IO`])
type Output<AB, B>;
/// Use a function from `A -> B` to transform something
/// akin to `F<A>` to something akin to `F<B>`.
fn map_<AB, B>(self, f: AB) -> Self::Output<AB, B>
where AB: F1<A, Ret = B>,
Self::Output<AB, B>: Equiv<To = F::T<B>>;
}