It seems that argument destructuring (Functions · The Julia Language) works for named but not anonymous functions (see examples below). Is there a reason for that, or am I just missing something as a newbie?
Thanks a lot!
# Works
f1((x1, x2)) = x1 + x2
f1([1, 2])
# Works
function f2((x1, x2))
x1 + x2
end
f2([1, 2])
# Does not work
(((x1, x2)) -> x1 + x2)([1, 2])
# Does not work
function f4()
function ((x1, x2))
x1 + x2
end
end
f4()([1, 2])
Another way of thinking about this is that () is not the tuple operator, , is. Adding more parentheses to (x, y) -> x + y to get ((x, y)) -> x + y doesn’t change anything, because in general adding more parentheses to an expression in Julia doesn’t change what that expression means. If you want to express that the first argument is itself a tuple, you need that extra comma: ((x, y),) -> x + y.
It is an unfortunate ugly case when there is just one parameter, and it is a tuple. If there are two parameters that are both tuples, the notation is the one I would expect:
julia> a = repeat([(1, 2)], 4);
julia> b = repeat([(3, 4)], 4);
map((((x, y), (i, j)) -> (println(x, y, i, j))), a, b);
I have experience in Haskell, so I get confused all the time I am mapping over a single tuple and things do not work as I expected (i.e., without needing the external parenthesis with trailing comma). However, Haskell does not have this problem because:
It is unfortunate, since one of the main usecases for tuple destructuring is crafting pipelines, exactly a case where having multiple arguments unpack from a single value can be very useful!
On the other hand, at least it’s not too ugly, and, in my opinion, it’s better than special-casing the parentheses syntax for one-line anonymous functions. I can’t think of a preferable solution, and at least it’s only one comma’s worth of ugliness.
One thing that helped me a little was to notice that map can take a variable number of streams to operate on (again differently from Haskell, if I remember right). Many times I was zipping many streams into a stream of tuples to then passing the stream of tuples to a map with an anonymous function that deconstructed each tuple to operate over its fields, when instead I could just pass the multiple streams as arguments to map (and deconstruct nothing in the anonymous function passed to map, but just take multiple parameters).