如何通过生成函数完成求两个元组之间各元素的和?


#1

下面是通过生成函数,完成一个元组各元素的求和。

@generated function sum3(t::NTuple{N, Any}) where {N}
    # This body is the "function generator"
    elements = [ :( t[$i] ) for i = 1:N ]
    expr = :( +($(elements...)) )
    return expr # The returned expression is the "generated function body"
end

@code_lowered sum3((1, 2.0, pi))

得到

CodeInfo(
1 ─ %1 = (Base.getindex)(t, 1)
│   %2 = (Base.getindex)(t, 2)
│   %3 = (Base.getindex)(t, 3)
│   %4 = %1 + %2 + %3
└──      return %4
)

我想类比于上边的代码,通过生成函数完成两个元组之间各元素的和,试了一天也没搞出来,不过写出来了个不是很完美的(下面的代码),可以完成求和,不过元组是套着的,啊啊啊,心态崩了。

@generated function add_tuples(t1::NTuple{N, Any}, t2::NTuple{N, Any}) where {N}
    # Create expression
    element1 = [:(t1[$i]) for i = 1:N]
    element2 = [:(t2[$i]) for i = 1:N]
    ex = :($(element1[1]) + $(element2[1]))
    for i = 2:N
        ex = quote $ex, $(element1[i]) + $(element2[i]) end
    end
    ex
end

得到

CodeInfo(
1 ─ %1  = (Base.getfield)(t1, 1, true)::Int64
│   %2  = (Base.getfield)(t2, 1, true)::Float64
│   %3  = (Base.sitofp)(Float64, %1)::Float64
│   %4  = (Base.add_float)(%3, %2)::Float64
│   %5  = (Base.getfield)(t1, 2, true)::Int64
│   %6  = (Base.getfield)(t2, 2, true)::Float64
│   %7  = (Base.sitofp)(Float64, %5)::Float64
│   %8  = (Base.add_float)(%7, %6)::Float64
│   %9  = (Core.tuple)(%4, %8)::Tuple{Float64,Float64}
│   %10 = (Base.getfield)(t1, 3, true)::Int64
│   %11 = (Base.getfield)(t2, 3, true)::Float64
│   %12 = (Base.sitofp)(Float64, %10)::Float64
│   %13 = (Base.add_float)(%12, %11)::Float64
│   %14 = (Core.tuple)(%9, %13)::Tuple{Tuple{Float64,Float64},Float64}
└──       return %14
) => Tuple{Tuple{Float64,Float64},Float64}

代码和问题是JuliaCon2018讲metaprogramming的[Notebook Chapter 12]。(https://github.com/FugroRoames/RoamesNotebooks)

实在不知道正确的怎么搞,求助! 谢谢:pray:


#2

只改寫了這句,但不知是否有更好的作法?

ex = quote ($ex)..., $(element1[i]) + $(element2[i]) end

#3

用 Base.Cartesian

julia> using Base.Cartesian

julia> @generated add_tuples(t1::NTuple{N,Any}, t2::NTuple{N,Any}) where {N} = :(@ntuple $N i -> t1[i] + t2[i])
add_tuples (generic function with 1 method)

julia> add_tuples((1,2,3), (4,5,6))
(5, 7, 9)

#4

这样就可以了啊:man_facepalming:,真的是神奇:exploding_head: