# Type inference: map + accumulate tuple recursively

**URL:** https://discourse.julialang.org/t/type-inference-map-accumulate-tuple-recursively/17648
**Category:** General Usage
**Tags:** question
**Created:** [November 17, 2018, 4:05pm UTC](https://discourse.julialang.org/t/type-inference-map-accumulate-tuple-recursively/17648 "2018-11-17T16:05:07Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [November 17, 2018, 4:05pm UTC](https://discourse.julialang.org/t/type-inference-map-accumulate-tuple-recursively/17648/1 "2018-11-17T16:05:08Z")

</div>

I have a function `f` that returns two results: the first one maps the argument to something, the second is a scalar. For the MWE, let

```julia
f(x::Real) = x + 1, abs2(x)
f(x::AbstractArray) = x .+ 1, sum(abs2, x)

```

Please treat these as a black box otherwise.

I would like to define an `f(::Tuple)` that calls `f` on each field, returns a tuple of the _first_ values and the _sum_ of the second values. I would like the compiler to be able to infer the return type. For example,

```julia
julia> f((-1, [-2], [-3.0, -4.0]))
((0, [-1], [-2.0, -3.0]), 30.0)

```

I tried

```julia
function _f(acc, ys, x, xs...)
    y, s = f(x)
    _f(acc + s, (ys..., y), xs...)
end

_f(acc, ys) = ys, acc

f(x::Tuple) = _f(0, (), x...)

```

but

```julia
julia> @code_warntype f((-1, [-2], [-3.0, -4.0]))
Body::Tuple{Tuple,Float64}
 1 1 ─ %1 = (getfield)(x, 1)::Int64 │  
   │ %2 = (getfield)(x, 2)::Array{Int64,1} │  
   │ %3 = (getfield)(x, 3)::Array{Float64,1} │  
   │ %4 = (Base.add_int)(%1, 1)::Int64 │╻╷ _f
   │ %5 = (Base.mul_int)(%1, %1)::Int64 ││╻ f
   │ %6 = (Base.add_int)(0, %5)::Int64 ││╻ +
   │ %7 = (Core.tuple)(%4)::Tuple{Int64} ││ 
   │ %8 = invoke Main._f(%6::Int64, %7::Tuple{Int64}, %2::Array{Int64,1}, %3::Array{Float64,1})::Tuple{Tuple,Float64}
   └── return %8 │  

julia> VERSION
v"1.1.0-DEV.671"

```

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [November 17, 2018, 4:13pm UTC](https://discourse.julialang.org/t/type-inference-map-accumulate-tuple-recursively/17648/2 "2018-11-17T16:13:37Z")

</div>

Also, just to clarify: I know how to use a generated function, I am asking for a recursive solution.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [November 17, 2018, 4:18pm UTC](https://discourse.julialang.org/t/type-inference-map-accumulate-tuple-recursively/17648/3 "2018-11-17T16:18:24Z")

</div>

This works:

```julia
function _f2(x, xs...)
    y, s = f(x)
    ys, ss = _f2(xs...)
    (y, ys...), s + ss
end

_f2() = (), 0

f(x::Tuple) = _f2(x...)

```

but why doesn’t the first one?

---

<div class="post-metadata">

### Author: ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)
#### Post date: [November 17, 2018, 5:27pm UTC](https://discourse.julialang.org/t/type-inference-map-accumulate-tuple-recursively/17648/4 "2018-11-17T17:27:13Z")

</div>

I’m guessing because in the second version it’s easier for the compiler to prove that the recursion is finite.

This reminded me of Jameson’s post here: [Efficient tuple concatenation - #8 by jameson](https://discourse.julialang.org/t/efficient-tuple-concatenation/5398/8) and explanation here: [Efficient tuple concatenation - #11 by jameson](https://discourse.julialang.org/t/efficient-tuple-concatenation/5398/11)

> [@Efficient tuple concatenation](https://discourse.julialang.org/t/efficient-tuple-concatenation/5398/11):
>
> It doesn’t call itself recursively on new values, only existing ones. This allows inference to trivially prove that it won’t need to solve the halting problem in order to do constant propagation.
