【问题标题】:Interpolating literals into each expression in an array using a for loop使用 for 循环将文字插入数组中的每个表达式
【发布时间】:2021-01-12 01:37:27
【问题描述】:

我有一个函数,我想在其中使用作为参数传递给函数的内插文字来评估表达式列表,并将结果分配给新数组。以前我可以很简单地做到这一点:

array_of_expr = Any[:(A * 5), :(B * 6 * T)]

arglist = [:A; :B; :T]
test_input = [1e5, 1e1, 100]

@eval begin
    function interpolate_all($(arglist...))
        result_array = $(Expr(:vcat, array_of_expr...))
    end
end

interpolate_all(test_input...)

返回预期结果:

2-element Array{Float64,1}:
 500000.0
 6000.0

(我知道@eval 的代码似乎不必要地复杂--这是因为在完整版代码中,arglist 的长度约为 500 项。这在完整版中导致了一些编译器错误代码,所以我在这里循环 array_of_expr 的尝试是我测试的一部分,以找出确切的错误,也帮助我更好地理解元编程/变量范围。)

我可以索引array_of_expr 并在此 MWE 中手动评估单个元素:



@eval begin
    function interpolate_one($(arglist...))
        result_array = similar(array_of_expr)
        println("evaluating $(array_of_expr[2])")
        result_array = $(array_of_expr[2])
        println(result_array)
    end
end

interpolate_one(test_input...)

返回:

evaluating B * 6 * T
6000.0

这是预期的行为。但是如果我尝试遍历array_of_expr,我会遇到各种错误。下面忽略迭代器i,只打印符号表达式:

@eval begin
    function interpolate_1by1($(arglist...))
        result_array = similar(array_of_expr)
        # this doesn't work, it just gives the symbolic expression, basically ignoring the $:
        for i in range(1, length=length(array_of_expr))
            result_array[i] = ($array_of_expr[i])
        end
        println(result_array)
    end
end

interpolate_1by1(test_input...)

下面报告i没有定义,我理解是因为expressions are evaluated in the global scope, not local

@eval begin
    function interpolate_1by1($(arglist...))
        result_array = similar(array_of_expr)
        # this doesn't work, i is undefined:
        for i in range(1, length=length(array_of_expr))
            result_array[i] = $(array_of_expr[i])
        end
    end
end

interpolate_1by1(test_input...)

有什么办法可以使这个工作吗?我已经尝试了引用的 SE 答案中的策略,但没有成功。

【问题讨论】:

    标签: julia metaprogramming


    【解决方案1】:

    你可以在编译时展开循环:

    @eval begin
        function interpolate_1by1($(arglist...))
            result_array = similar($array_of_expr)
            $((quote
                result_array[$i] = $(array_of_expr[i])
            end for i in 1:length(array_of_expr))...)
            return result_array
        end
    end
    

    展开后类似

    function interpolate_1by1($(arglist...))
        result_array = similar($array_of_expr)
        result_array[1] = $(array_of_expr[1])
        result_array[2] = $(array_of_expr[2])
        ...
        return result_array
    end
    

    【讨论】:

    • 谢谢,这很好用,我想我自己不会从文档中弄清楚这一点。我忘记了在代码的主要版本中,array_of_expr 未指定为 Any,因此解决方案引发了无法将 Float64 ($(array_of_expr[i]) 转换为 Expr (result_array[:i]) 的错误。我通过在类似的调用中添加参数 Float64 轻松解决了这个问题:similar($chemJ_local[3], Float64)——以防万一任何人在阅读时遇到类似的情况。
    猜你喜欢
    • 2014-09-17
    • 2015-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    相关资源
    最近更新 更多