Feature Request: if no `__` is specified then insert into first argument
Currently
@_ a |> f(_, b) is needed but in other tools like Lazy.jl and R's magrittr which allows the first argument to be the previous one without _ e.g.
@_ a |> f(b) would be equivalent to f(a,b) and @_ a |> f(_, b)
I think being explicit is a virtue of this package. Automatically inserting __ as the first (or should it be last?) argument would also make it impossible to chain functions which do already return a closure:
g(x) = begin y=exp(x); z -> z .* y end
@_ data |> filter(abs(_)>1, __) |> g(x) |> scatter
(Note that @_ a |> f(_, b) means a |> f(identity, b), but I assume you meant @_ a |> f(__, b) with two underscores.)
Interesting argument. But g(x)() would work. And also it's more often the case that we need _ as first argument then it is to get a closure as return from a function.
Ah right, there's a way... and I guess |> g(x)(__) |> scatter would likewise be the most explicit way to write my example today.
Do you have examples of where you'd want first rather than last-argument __? The tests have many map / sum / filter (last) and one sort (only).
The way that Lazy.jl deals with it is that
@> and @>> are for first and last. Perhaps @_ will optionally allow _ anywhere and also have a @_last macro?
Also
@_ obj begin
function1
function2
function3
end
without needing |> would be nice.
Overall I think this is an interesting idea, and might resolve some of the uglyness of __. I think the rule might be:
- For
Expr(:call)on the right hand side of an|>expression, if__doesn't appear in the call, insert it as the last argument.
Thus, we'd have the following work:
@_ data |> filter(abs(_)>1) |> map(_+1) |> scatter
If there's no piping present, no __ would be inserted.
The need to explicitly use __ for use with functions-which-return-functions is unfortunate, however, and would make Underscores.jl unattractive for use with libraries which are designed with currying in mind. @tkf — that's probably your case case?
Another option could be to... just add more underscores, and have a macro @__ which does this transformation, leaving @_ as it is?
It's worth keeping in mind that this package is not just about pipelines, though that's one of the nice use cases for it (I think where you mention _ above, you really mean __.)
without needing
|>would be nice.
Personally I don't like the implicit chaining syntax in Lazy.jl at all so I'd rather not emulate it!
Yeah, transducers are always "curried". So, we'd need extra () like @_ collection |> Filter(abs(_) > 1)() |> sum if __ is automatically inserted.
@xiaodaigh I still think this is a good idea; we'd just need to modify it a little.
What if we implemented a @__ macro which followed the rule I laid out in https://github.com/c42f/Underscores.jl/issues/17#issuecomment-681630491 ? Would that serve your use case?
A bit crazy idea is to use some infix combinator like
julia> f $ args::Tuple = x -> f(args..., x)
f $ a = x -> f(a, x)
$ (generic function with 2 methods)
julia> @_ -3:3 |> filter$(abs(_)>1) |> map$(_+1) |> collect
4-element Array{Int64,1}:
-2
-1
3
4
Though it's not ideal that f$(x) may or may not splat x when its type is unknown. You'd have to write f$(x,) or f$(x...,) to be very specific.
I've found a couple of uses of @_ in the last few weeks while where having __ as the last parameter wouldn't work. For example
@_ read(`git status --porcelain`) |> String |> split(__,'\n')