But as always, depends on where you come from. I mostly deal with lisp languages nowadays, so guessing it's just my view that the line quoted above seems complex enough to not be interested one bit in Rust.
Bt then again, maybe it depends on where you come from.
The equivalent in Haskell would be "compose :: (a -> a) -> (a -> a) -> a -> a", which lacks "impl" because it boxes all closures (each closure in Rust has its own type), and lacks "Fn" because it doesn't care about what kind of access the closure needs to its context (Rust distinguishes between Fn, FnMut and FnOnce). Still, the Rust is only a tiny bit more complicated than the Haskell.
#![feature(trait_alias)]
trait Map<T> = Fn(T) -> T;
fn compose <T>(f1: impl Map<T>, f2: impl Map<T>) -> impl Map<T> {
|n| f1(f2(n))
}template<typename T> using Map = std::function<T (T)>;
fn compose<T, F: Fn(T)->T>(f1: F, f2: F) -> F { fn compose<T, F: Fn(T) -> T, G: Fn(T) -> T>(f: F, g: G) -> impl Fn(T) - > T
or: fn compose<T, F, G>(f: F, g: G) -> impl Fn(T) -> T
where F: Fn(T) -> T, G: Fn(T) -> Thttps://doc.rust-lang.org/nightly/std/iter/trait.Iterator.ht...
... and `impl Trait` exists to be able to have return types which are difficult, verbose, or impossible to name.
compose(|x| x, |x| x)
because the closures have the same type.It's a fun little thing, and a good example of why impl Trait in argument position is a really nice addition to Rust, even though based on what we were originally excited about (impl Trait in return position for returning Iterators and other such things), the argument position form didn't seem so important.
fn compose<T, F: Fn(T) -> T>(f1: F, f2: F) -> F
As far as I'm aware the only way to write a function like that is fn compose<T, F: Fn(T) -> T>(f1: F, f2: F) -> F {
f1
}
and even then you can only call it like this let clos = |x| 2 * x;
compose(clos, clos); fn compose<T>(
f1: impl Fn(T)->T,
f2: impl Fn(T)->T
) -> impl Fn(T)->T
{
// both arguments as well as the returned value
// are functions which take and return the generic type T.
// (to be precise, they implement the Fn trait).
}
let returned_function = compose(|val| val == 1, |val| val < 0);
let value: bool = returned_function(true);Stuff like this? You mean closures? That's what you find amazing? What is considered ordinary in other programming languages is considered amazing in Rust. Amazing.
> It’s simultaneously: relatively clean code, very efficient and type-safe. I like it.
You like it? Do you work for mozilla? If there is a tech evangelist of the year award, I will vote for you. I've never seen someone take absolutely nothing and try to spin it into something positive.
Edit: Instadownvotes by the evangelists. I like it!
If you'd please review https://news.ycombinator.com/newsguidelines.html and take the intended spirit of this place more to heart, we'd be grateful.
It's not that lambdas themselves are hard, it's that they made it work with all of the other constraints of the language.