"do" notation over tuples

What am I doing wrong here?

julia> inds = [(i,j) for i in 1:3, j in 1:5]
3×5 Array{Tuple{Int64,Int64},2}:
 (1, 1)  (1, 2)  (1, 3)  (1, 4)  (1, 5)
 (2, 1)  (2, 2)  (2, 3)  (2, 4)  (2, 5)
 (3, 1)  (3, 2)  (3, 3)  (3, 4)  (3, 5)

julia> map(((i,j),) -> i+j, inds)
3×5 Array{Int64,2}:
 2  3  4  5  6
 3  4  5  6  7
 4  5  6  7  8

julia> map(inds) do ((i,j),) i+j end
ERROR: BoundsError: attempt to access 1
  at index [2]
Stacktrace:
 [1] indexed_iterate(::Int64, ::Int64, ::Nothing) at ./tuple.jl:69
 [2] (::getfield(Main, Symbol("##94#95")))(::Tuple{Int64,Int64}) at ./REPL[66]:1
 [3] iterate at ./generator.jl:47 [inlined]
 [4] _collect at ./array.jl:632 [inlined]
 [5] collect_similar(::Array{Tuple{Int64,Int64},2}, ::Base.Generator{Array{Tuple{Int64,Int64},2},getfield(Main, Symbol("##94#95"))}) at ./array.jl:561
 [6] map(::Function, ::Array{Tuple{Int64,Int64},2}) at ./abstractarray.jl:1995
 [7] top-level scope at none:0
julia> map(inds) do (i,j) i+j end
3×5 Array{Int64,2}:
 2  3  4  5  6
 3  4  5  6  7
 4  5  6  7  8

The syntax for do notation is a little confusing — it takes arguments as x, y, z and not (x, y, z). It’s clearer if we look at this on multiple lines:

map(inds) do i, j
   i+j
end

The version above takes two arguments called i and j;

map(inds) do (i, j)
   i+j
end

This one destructures a single argument into a tuple.

3 Likes

Oh weird, could have sworn I’d already tried that. Thank you!

1 Like

Why not just sum?

julia> inds = [(i,j) for i in 1:3, j in 1:5]
3×5 Array{Tuple{Int64,Int64},2}:
 (1, 1)  (1, 2)  (1, 3)  (1, 4)  (1, 5)
 (2, 1)  (2, 2)  (2, 3)  (2, 4)  (2, 5)
 (3, 1)  (3, 2)  (3, 3)  (3, 4)  (3, 5)

julia> sum.(inds)
3×5 Array{Int64,2}:
 2  3  4  5  6
 3  4  5  6  7
 4  5  6  7  8

What I posted isn’t the real problem. For a DSL I made a For that works like map, so I can write things like

For(inds) do (i,j)
    f(i,j)
end

Aha, OK I didn’t imagine that, so @yurivish reply is good enough for this.

1 Like