首页 > 解决方案 > Julia 创建一个函数的多个稍作修改的版本

问题描述

我有一个看起来像的功能

function eom!(du, u, p)
    @views a, b = u[:,1], u[:,2];
    @views da, db = du[:,1], du[:,2];

    y = # some stuff involving p and a;
    da .= f(a, b, y);
    db .= g(b, a);
end

我现在想创建第二个完全相同的函数,除了最后一行读取

db .= g(b, y);

我怎样才能最干净地做到这一点?当然,我可以只是复制和粘贴,然后给函数命名略有不同,但这似乎并不理想,尤其是如果我后来想要更多的函数,其中的第二个参数g可能是别的东西。也许有一种方法可以将eom!一个表达式(通过参数p)传递给函数,该表达式将指定的第二个参数g?或者有没有办法可以制作一些eom_generator可以输出我想要的所有功能的功能?也许宏是执行此操作的核心工具,但我不确定。

标签: functionmacrosclosuresjuliametaprogramming

解决方案


你可以产生一个闭包:

function eom_generator(g)
    return function eom!(du, u, p)
        @views a, b = u[:,1], u[:,2]
        @views da, db = du[:,1], du[:,2]

        y = nothing # some stuff involving p and a;
        da .= f(a, b, y)
        db .= g(a, b, y)
    end
end

const eom1! = eom_generator((a, b, y) -> g(b, a))
const eom2! = eom_generator((a, b, y) -> g(b, y))

但由于这是微分方程的核心,因此请务必测试您是否没有任何性能问题。

如果您决定确实需要元编程,则可以@eval在循环中使用:

for (i, expr) in enumerate((:(g(b, a)), :(g(b, y))))
    @eval function $(Symbol("eom", i, "!"))(du, u, p)
            @views a, b = u[:,1], u[:,2]
            @views da, db = du[:,1], du[:,2]

            y = nothing # some stuff involving p and a;
            da .= f(a, b, y)
            db .= $expr
        end
    end
end

推荐阅读