Именованные аргументы без естественных дефолтов в Julia

Вопрос о "лучшей практике" в Джулии. Я прочитал this и this. У меня есть функция

function discount_rate(n, fv, pmt, pv; pmt_type = 0)
...
end

Проблема прямо сейчас - мне нужно вызвать метод следующим образом

discount_rate( 10, 10, 10, -10 )

Не ясно, что означают эти аргументы - даже я забыл. Мне бы хотелось написать

discount_rate( n = 10, fv = 10, pmt = 10, pv = -10 )

Это яснее: легче читать и понимать. Но я не могу определить свой метод, аргументируя аргументы keywords аргументами или optional аргументами, потому что у них нет естественных значений по умолчанию. С точки зрения дизайна, есть ли рекомендуемый способ этого?

Ответ 1

Может сделать следующее:

function discount_rate(;n=nothing,fv=nothing,pmt=nothing,pv=nothing,pmt_type=0)
    if n == nothing || fv == nothing || pmt == nothing || pv == nothing
        error("Must provide all arguments")
    end
    discount_rate(n,fv,pmt,pv,pmt_type=pmt_type)
end

function discount_rate(n, fv, pmt, pv; pmt_type = 0)
    #...
end

Ответ 2

В качестве продолжения, было немного утомительно иметь (пере) писать ключевые слова только для функций, которые у меня уже были. Вдохновленный Iain ответом выше, я написал макрос, который по существу делает то же самое...

macro make_kwargs_only( func, args... )
 quote
  function $( esc( func ) )( ; args... )
   func_args = [ arg[2] for arg in args ]
   return $( esc( func ) )( func_args... )
  end
 end
end

Итак, например

f( a, b ) = a/b
@show f( 1, 2 )
f(1,2) => 0.5

Создание своего ключевого слова-партнера дает

@make_kwargs_only f a b
@show f( a = 1, b = 2 )
f(a=1,b=2) => 0.5

Обратите внимание, что это не общий случай. Здесь порядок аргумента имеет решающее значение. В идеале мне бы хотелось, чтобы макрос работал одинаково для f( a = 1, b = 2 ) и f( b = 2, a = 1 ). Это не так.

@show f( b = 2, a = 1 )
f(b=2,a=1) => 2.0

Итак, теперь, в качестве взлома, я использую methods( f ), если не могу запомнить порядок аргументов. Любое предложение о том, как переписать макрос для обработки обоих случаев, приветствуется... возможно, способ сортировки func_args в определении макрофункции на основе сигнатуры функции func?