I am working on a library where I cannot avoid heterogeneous collections, and I want type stable code. The MWE below is a typical (but heavily simplified) example of something I would do (transformations, accumulation), but I find it hard to get the compiler to infer the type.
function next_ix(acc, x::AbstractArray)
l = length(x)
acc + l, acc + (1:l)
end
next_ix(acc, x::Number) = acc+1, acc+1
function indexes(xs)
acc = 0
map(x -> (((acc, ix) = next_ix(acc, x)); ix), xs)
end
@inferred indexes((1,1,1)) # error, infers Tuple{Any,Any,Any}
@inferred indexes((1,1:2,ones(2,2))) # ditto
The question is twofold: (1) how should I deal with the specific problem above, (2) how to do this in general, so that I get maintainable and easy to read code.
Is it even sensible to try to use basic constructs in Base
for this? With @cstjean’s excellent Unrolled.jl, things become very easy:
using Unrolled
@unroll function indexes2(xs)
acc = 0
result = ()
@unroll for x in xs
acc, ix = next_ix(acc, x)
result = (result..., ix)
end
result
end
@inferred indexes2((1,1,1))
@inferred indexes2((1,1:2,ones(2,2)))
so should I just keep using that everywhere?