using Test # for Test.@inferred
g(::Val{n}) where {n} = ntuple(i -> one(Rational{BigInt}), Val{n}()) # constructs an example tuple of specified length
map(+, g(Val{30}()), g(Val{30}())); # warm up
@inferred map(+, g(Val{30}()), g(Val{30}())) # works fine
map(+, g(Val{40}()), g(Val{40}())); # warm up
@inferred map(+, g(Val{40}()), g(Val{40}())) # ERROR: return type NTuple{40, Rational{BigInt}} does not match inferred return type Tuple
I guess that using ntuple instead of map could be a workaround for this type inference issue.
But I’m curious, are there any similar gotchas that I should keep in mind?
Eventually I wrote these functions to fix my type inference issues (they’re an unary and a binary version):
# Like map, but with better type inference.
map_tuple(f::Fun, a::NTuple{len}) where {Fun <: Function, len} =
ntuple(
let a = a
i -> f(a[i])
end,
Val{len}())
# Like map, but with better type inference.
map_tuple(f::Fun, a::T, b::T) where {Fun <: Function, len, T <: NTuple{len}} =
ntuple(
let a = a, b = b
i -> f(a[i], b[i])
end,
Val{len}())
They work fine, but I wonder if a somewhat generalized version should really be in Julia Base? Pretty sure this is an issue that comes up often, and implementing a solution is out-of-reach for most newcomers.