Юлия создала несколько слегка модифицированных версий функции - PullRequest
3 голосов
/ 14 февраля 2020

У меня есть функция, которая выглядит как

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, которая может выводить все функции, которые я хочу? Возможно, макросы являются центральным инструментом в этом, но я не уверен.

1 Ответ

7 голосов
/ 14 февраля 2020

Вы можете создать замыкание:

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 в al oop:

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
...