Description
I don't think there is any rush, I just wanted to get this idea out of my head.
The proposal has two parts:
- Forward and backward piping operators
a |> b = b(a) // forward piping
a <| b = a(b) // backward piping
The arrow points in which direction the value flows. The forward piping allows programming in UNIX-pipes style - allows cleanly doing multi-step processing without defining too many helper functions.
Backward piping is going to be useful with more "functional style" programs - it allows avoiding some parentheses (pretty much like Haskell's $
).
- In Jsonnet curried functions are not that common, so in order to make the use of (1) practical, there needs to be a way to choose an argument for piping. I think I came up with a nice syntax.
I'll start with an example:
["foo", "FOO", "bar"] |> std.map(capitalize, _) |> std.sort | std.uniq
So the idea is that instead of an argument _
can be "passed" - a hole where a value can be put. The _
is interpreted this way only when it is passed as an argument. No complex expressions involving it are allowed. f(2 + _)
is not allowed.
So f(a, b, c, _, d) = function(x) f(a, b, c, x, d)
.
It's unambiguous which expression is wrapped in a function - it's always just the function application.
It would be possible to also do things like this:
arrayOfStrings |> std.filter(std.startsWith(_, "prefix"), _) |> something
The issue is that _
is a valid identifier. It's unfortunate. We can either find a new symbol or interpret it this way only when there is no local variable named that. This can be handled during desugaring, though it's going to be quite annoying. We should also discourage using _
(or anything starting with _
for future proofing) if we go with that - possibly using Linter.