Are there any good crates for functional programming? That is, crates that provide useful but relitively trivial traits/functions for functional programming? For example, I needed a function to pull out the first element of a pair so I could call my_pair_option.map(first) instead of my_pair_option.map(|(a, _)| a) as I find the former more readable. I could use the following but implementing things like this myself for every project doesn't really make sense (it's easier to just write my_pair_option.map(|(a, _)| a)).
pub trait Pair {
type First;
type Second;
fn first(self) -> Self::First;
fn second(self) -> Self::Second;
}
impl<A, B> Pair for (A, B) {
type First = A;
type Second = B;
fn first(self) -> A {
self.0
}
fn second(self) -> B {
self.1
}
}
impl<'a, A, B> Pair for &'a (A, B) {
type First = &'a A;
type Second = &'a B;
fn first(self) -> &'a A {
&self.0
}
fn second(self) -> &'a B {
&self.1
}
}
pub fn first<P: Pair>(pair: P) -> P::First {
pair.first()
}
pub fn second<P: Pair>(pair: P) -> P::Second {
pair.second()
}
Unfortunately, many of the fun tools require features rust doesn't currently have: HKT, variadic arguments, custom implementations of Fn* (unstable), etc...
Not on stable. On nightly, one can directly implement Fn* (unlikely to be stabilized) or return a closure using impl Trait syntax (hopefully going to be stabilized in the near future). Here's a compose function:
Unfortunately, this restricts the impl to FnMut. With the fn_traits and unboxed_closures features, it's possible to abstract over FnMut, FnOnce, and Fn. Example:
I... wow. It never occurred to me that impl Trait could be used for the Fn traits. I currently have my own ungodly solution for making functions like these, in the form of a unboxed-closure-generating macro; I wonder how many of my usages of it could be replaced with an impl Fn*.
...then again, it also never occurred to me that Fn traits could be a candidate for conditional trait implementation, which kind of tosses the idea right back out the window! Though I guess it's at least good enough for impl FnOnce
(it occurs to me now that I apparently already knew the answer to my own question; but I had forgotten until I saw your example)
Here's an odd and unpolished functional tool, a helper for recursive closures: Fix from crate odds. The crate doesn't otherwise have any "functional tools" I think..
Its only ever real use looks like this:
// check all parent links
let check_parents = |f: Fix<_, _>, entry| {
let entry: &Entry<_, _> = entry;
entry.children.iter().all(|c| ptr_eq(c.parent, entry) && f.call(&**c))
};
assert!(Fix(&check_parents).call(&*m.root));
With unstable features, the explicit .call() can be removed. Not sure if the other lifetime and type inference related drawbacks can be improved upon.
Edit: Ok, adding a simple fix function makes it much easier to call the combinator and have type inference work with you. Updated usage: