This is a fun thread! But I want to draw attention to the heart of the proposal.
What we want
-
Easy-to-type, left-to-right chainable function composition
Like x |> f |> g
or x.f().g()
instead of g(f(x))
.
-
Easy-to-type partial function application
We already have x -> f(x, a)
, but we want f(_, a)
, or even just f(a)
if the first argument is implied.
We have this with macros
Both these conveniences are readily offered with, e.g., Chain.jl
(as noted above).
using Chain
@chain "hello" split("") _.^2 join("•") uppercase
# …is the same as…
uppercase(join(split("hello", "").^2, "•"))
So why are we still talking about it? Well:
What @uniment’s MethodChains.jl
proposal offers
The main selling point seems to be repurposing brace syntax { }
to be function composition with built-in support for partial application.
There is a lot more to this proposal, but I’m not so sure about the rest of it.
Using braces as a Chain.jl
syntax
We can achieve the core of this proposal simply by transforming the brace syntax into a Chain.jl
-style chain:
using Chain
using MacroTools: postwalk
bracechains(expr) = postwalk(expr) do node
if node isa Expr && node.head ∈ (:braces, :bracescat)
arg = gensym()
:($arg -> @chain $arg $(node.args...))
else
node
end
end
To enable this syntax transformation in the REPL, run:
pushfirst!(Base.active_repl_backend.ast_transforms, bracechains)
Then you can do things like:
julia> "chains" |> {
split("")
_ .^ 2
join("•")
uppercase
}
"CC•HH•AA•II•NN•SS"
julia> f = {repr, reverse, "(( $_ ))"}
#73 (generic function with 1 method)
julia> f(0xCAFE)
"(( efacx0 ))"
Differences
Personally, I find x |> {f, g}
better than x.{f, g}
, since to a Julian the former looks like function application while the latter looks like broadcasting.
I also prefer Chain.jl
’s use of _
as the anonymous argument over it
or any alphanumeric name.
Overall, this brace syntax is nice, but I’m not convinced it’s that much better than using Chain.jl
as-is. Though nobody can deny it’s easier to type!
I think we should keep playing around like this… but not get too carried away! In the end, the simpler the better.