I want to do an array comprehension from a list of ranges in a quote but I get a syntax error.
loops = [:(i=1:2), :(j=1:3)]
:([i+j for :(loops...)]) # ideally maps to [i+j for i=1:2, j=1:3]
syntax: invalid iteration specification
How can I work around this?
This can’t work I think because macros need to have valid Julia syntax at every step and :(for something)
is not valid Julia, so :(for $(something))
also does not work.
(You probably meant to use $
inside the quote and not :
but this doesn’t change anything)
I don’t really see how to work around this in your case, since I don’t know what problem you are trying to solve. Can you provide more context? Like what do you want to do and why do you think a macro is the solution?
Interpolation indeed does not seem to work.
In any case, you can construct the expression explicitly:
julia> Expr(:comprehension, Expr(:generator, :(i+j), loops...))
:([i + j for i = 1:2, j = 1:3])
julia> eval(ans)
2×3 Matrix{Int64}:
2 3 4
3 4 5
2 Likes
The above solution works great though I’m not using it now but I now have a new problem where generated functions apparently don’t work with comprehensions.
My use case it to traverse a complicated nested structure to get some data. Here is the code that creates the quote for the generated function
h = IDSPath("time_slice/:/profiles_2d/0/psi")
function _getindex_gen2(ids, h::Type{IDSPath{H}}) where {H}
path = _IMAS_HASH_MAP[H]
I = :(ids.ids)
I, indices, ranges = _parse_ids_path(I,path)
if !isempty(indices)
reverse!(indices)
reverse!(ranges)
for (ind, r) in zip(indices,ranges)
I = :([$I for $ind in $r])
end
end
return I
end
_getindex_gen2(x,h) #-->:([((ids.ids.time_slice[i1]).profiles_2d[0]).psi for i1 = 1:length(ids.ids.time_slice)])
My question now is to figure out how to avoid the comprehension entirely but get the same result for the retrieved data i.e. a vector of vectors of vectors… for the data that generally has the same shape but could have different sizes.
For future readers I found a workaround that works. Basically I have to manually create the arrays like so
for (ind,r) in zip(inds,ranges)
a = Symbol("arr",'_',ind)
I = quote
$a = let $a
$ind,r... = $r
$a = [$I]
for $ind in r
push!($a, $I)
end
$a
end
end
end
Not sure if there is a better way but this works.