SimpleUnderscores.jl

Because there weren't enough of these packages already
Author MasonProtter
Popularity
11 Stars
Updated Last
9 Months Ago
Started In
February 2023

SimpleUnderscores.jl

SimpleUnderscores.jl aims to provide yet another way to locally construct anonymous functions where the arguments do not need to be listed before they are used in the body, but taking an approach that differents from Underscores.jl with less complicated scoping rules. See also JuliaLang/julia/issues/38713.

By default, it exports one macro, @>. An expression acted on by @> interprets underscores _ as a placeholder for a function argument. Hence, @> _ + 1 means the same thing as x -> x + 1. A bare underscore _ always is the first argument to the function:

julia> using SimpleUnderscores

julia> map(@> _ + _, [1,2,3])
3-element Vector{Int64}:
 2
 4
 6

Multiple Arguments

Click to expand

If you want to write a function acting on multiple arguments, you can write for instance _4 to mean the fourth argument. The function returned will take as many arguments as the highest argument placeholder number specified.

julia> λ = @> _ + _3;

julia> λ(5, 6, 7)
12

julia> λ(5,6)
ERROR: MethodError: no method matching (::var"#23#24")(::Int64, ::Int64)
Closest candidates are:
  (::var"#23#24")(::Any, ::Any, ::Any)
julia> map(@> _1.a + _2.b, [(;a=1,), (;a=2)], [(;b=3), (;b=4)])
2-element Vector{Int64}:
 4
 6

You can also use __ to signify varargs:

julia> f = @> _ + __[end];

julia> f(1,2,3,4,5,6,7,8,9)
10

Main limitation: dealing with tuples and commas

Click to expand Because the parser is such that [commas parse tighter than macros](JuliaLang/julia#36547 (comment)), when you write code like
map(@> _ + _, [1, 2])

this will actually get parsed as map(@>(((_ + _), [1, 2]))) rather than map(@>(_ + _), [1, 2]), but SimpleUnderscores will then macroexpand this to something like map(((x -> x + x), [1, 2])...,) so that we get the desired behaviour.

Unfortunately though, SimpleUnderscores.jl cannot tell the difference between @> (_, 1) and (@> _, 1), which means that if you want to write an anonymous function using SimpleUnderscores.jl that returns a Tuple, you need to write something like @> tuple(_, 1). The potential for fixing this is being discussed here: JuliaLang/julia/issues/36547.

This parsing behaviour also unfortunately means that a somewhat confusing error gets thrown if you try to construct a Tuple at the top level containing @>:

julia> @> _, [1] # Doesn't work :(
ERROR: syntax: "..." expression outside call around REPL[39]:1
   
julia> (@> _, [1]) # Also doesn't work :(((
ERROR: syntax: "..." expression outside call around REPL[40]:1
   
julia> ((@> _, [1]),) # At least this works.
(var"#31#32"(), [1])

but you should probably just use @>( ... ) instead in these case. Follow this PR for any news on a potential fix: JuliaLang/julia/pull/48750

Nested macros

Click to expand

Macros appearing inside a @> macro are recursively hit with macroexpand in the approporiate module, this is to make sure that things like @> filter(@> _.a > 1, _) correctly work.

Other names

Click to expand

There's two other, unexported macros inside the package, @-> and @_ which are the exact same as @> but some people may prefer the other names. If you prefer that, then you can simply do using SimpleUnderscores: @_ or using SimpleUnderscores: @->.

Required Packages

Used By Packages

No packages found.