`JuliaLang:master`

← `stevengj:curry`

opened 07:10PM - 08 Dec 17 UTC

This PR addresses #554, #5571, and #22710 by "currying" underscores in function …calls like `f(_,y)` into anonymous function expressions `x -> f(x,y)`. (Note that `_.foo` works and turns into `x -> x.foo` since it is equivalent to a `getfield` call, and `_[i]` works and turns into `x -> x[i]`, since it is equivalent to a `getindex(_,i)` call.)
This will help us get rid of functions like `equalto` (#23812) or `occursin` (#24967), is useful for "destructuring" as discussed in #22710, and should generally be convenient in lots of cases to avoid having to explicitly do `x -> f(x,y)`.
Some simplifying design decisions that I made:
* The currying is "tight", i.e. it only converts the immediately surrounding function call into a lambda, [as suggested by](https://github.com/JuliaLang/julia/issues/22710#issuecomment-314259250) @JeffBezanson (and [as in Scala](https://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#placeholder-syntax-for-anonymous-functions)). So, e.g. `f(g(_,y))` is equivalent to `f(x -> g(x,y))`. (Note that something like `find(!(_ in c), y)` will work fine, because the `!` operator works on functions; you can also use `_ ∉ c`.) Any other rule seems hard to make comprehensible and consistent.
* ~~Only a single underscore is allowed. `f(_,_)` throws an error: this case seems ambiguous to me (do you want `x -> f(x,x)` or `x,y -> f(x,y)`?), so it seemed better to punt on this for now. We can always add a meaning for multiple underscores later.~~ Similar to Scala, multiple underscores are converted into multiple arguments in the order they appear. e.g. `f(_,y,_)` is equivalent to `(x,z) -> f(x,y,z)`. See [rationale below](https://github.com/JuliaLang/julia/pull/24990#issuecomment-350879561).
The implementation is pretty trivial. If people are in favor, I will add
- [x] Tests
- [x] Documentation
- [ ] Fix interaction with broadcasting `f.(x, _)`
- [ ] Fix interaction with keyword arguments `f(x; y=_)`
- [ ] Support chained comparisons, e.g. `3 ≤ _ ≤ 10`, since they parse as a single expression?