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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! Higher-order functions (functions that operate on functions)

/// Useful functions exported by `tool::functor`.
pub mod prelude {
    #[doc(inline)]
    pub use super::{compose, fix, flip};
}

/// Compose two functions.
///
/// Takes functions `f` and `g` and returns `f ∘ g = |a: A| f(g(a))`.
pub fn compose<A, B, C, F, G>(f: F,  g: G) -> impl Fn(A) -> C
    where G: Fn(A) -> B,
          F: Fn(B) -> C,
{
    move |a: A| { f(g(a)) }
}

/// Flip the argument order of a two-parameter function.
///
/// Specifically, `flip(f: Fn(a: A, b: B) -> C) = |b: B, a: A| f(a, b)`.
pub fn flip<F, A, B, R>(f: F) -> impl Fn(B, A) -> R
    where F: Fn(A, B) -> R
{
    move |a, b| f(b, a)
}

/// A Y-Combinator.
///
/// Takes a function `f` and returns a fixpoint of `f`.
///
/// In English, this allows you to define a recursive closure, something that's
/// normally quite hard to do in rust. Rather than try to explain it, here's an
/// illustration that should speak for itself (as long as you know the recursive
/// definition of Fibonacci numbers).
///
/// ```rust
/// use tool::prelude::*;
///
/// let fib = fix(|f, x| {
///     if x == 0 || x == 1 {
///         x
///     } else {
///         // `f` is `fib`
///         f(x - 1) + f(x - 2)
///     }
/// });
/// assert_eq!(55, fib(10));
/// ```
pub fn fix<A, B, F>(f: F) -> impl Fn(A) -> B
    where F: Fn(&Fn(A)-> B, A) -> B
{
    use std::cell::Cell;

    move |a: A| {
        // Hopefully optimized away. Can probably use some unsafe magic to help the optimizer...
        let tmp_fn = |_: A| -> B { panic!("Hmm... not good.") };
        let (fun_holder, fun);
        fun_holder = Cell::new(&tmp_fn as &Fn(A) -> B);
        fun = |ai: A| { f(fun_holder.get(), ai) };
        fun_holder.set(&fun as &Fn(A) -> B);
        f(fun_holder.get(), a)
    }
}

// TODO: Someday
// pub struct Uncurry<F>(F);
//
// impl<T, F> FnOnce<(T,)> for Uncurry<F>
//     where F: FnOnce<T>
// {
//     type Output = F::Output;
//
//     extern "rust-call" fn call_once(self, (args,): (T,)) -> F::Output {
//         self.0.call_once(args)
//     }
// }
//
// impl<T, F> FnMut<(T,)> for Uncurry<F>
//     where F: FnMut<T>
// {
//     extern "rust-call" fn call_mut(&mut self, (args,): (T,)) -> F::Output {
//         self.0.call_mut(args)
//     }
// }
//
// impl<T, F> Fn<(T,)> for Uncurry<F>
//     where F: Fn<T>
// {
//     extern "rust-call" fn call(&self, (args,): (T,)) -> F::Output {
//         self.0.call(args)
//     }
// }
//
//
// pub fn uncurry<A, F>(f: F) -> Uncurry<F> {
//     Uncurry(f)
// }