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
crate::define! {
    /// Identity function. Returns its input.
    /// ```text
    /// λx.x
    /// ```
    pub fn Identity ::= { Input. { Input }};
    /// Takes two values and returns the first.
    /// ```text
    /// λa.λb.a
    /// ```
    pub fn FirstOf ::= { Input. { Constant<Input> }};
    /// Returns its type parameter, ignoring input.
    /// ```text
    /// λv.I
    /// ```
    pub fn Constant<I> ::= { _Ignored. { I }};
    /// Takes two values and returns the second.
    /// ```text
    /// λa.λb.b
    /// ```
    pub fn SecondOf ::= { _Ignored. { Identity }};
    
    /// Composes a function with another.
    /// Note that this returns a [`Composed`], for more ergonomic point-free form.
    /// ```text
    /// λf.λg.λx.fgx
    /// ```
    pub fn Compose ::= { A. B. { Composed<A, B> }};
    
    /// The composition of two functions. See [`Compose`].
    /// ```text
    /// λx.FGx
    /// ```
    pub fn Composed<Fn, OtherFn> 
        ::= { Input. { Fn, { OtherFn, Input }}}
    where
        OtherFn: Input,
        Fn: {OtherFn, Input};
    
    /// Takes a function and an input, and returns the function applied to said input.
    /// ```text
    /// λf.λx.fx
    /// ```
    pub fn Apply
        ::= { Fn. Input. { Fn, Input }}
    where
        Fn: Input;

    /// S combinator. Takes three inputs, and applies the first to the second and third.
    /// ```text
    /// λx.λy.λz.xz(yz)
    /// ```
    pub fn Sheinfinkel ::= { X. Y. Z. {X, Z, { Y, Z }}} where
        X: Z, Y: Z, {X, Z}: {Y, Z};

    /// Takes a function that takes two arguments and the first argument to said function,
    /// and returns a function that takes the second argument and runs the function with both.
    /// See [`Curried`].
    /// ```text
    /// λf.λx.(λy.fxy)
    /// ```
    pub fn Curry
        ::= { Fn. Input. { Curried<Fn, Input>}};
    
    /// Function that curries the first type argument with the second and the input. See [`Curry`].
    /// ```text
    /// λy.FXy
    /// ```
    pub fn Curried<Fn, X> ::= { Y. { Fn, X, Y }} where
        Fn: X,
        {Fn, X}: Y;
}