Как я могу передать аргументы ключевого слова функции `range` из другой функции и сохранить гибкость пользователя с помощью Джулии? - PullRequest
1 голос
/ 08 мая 2020

Пишу свой первый модуль на Юлии. У меня есть функция f, которая будет использовать вектор или диапазон для некоторых вычислений. Я хотел бы создать метод этой функции, который будет создавать диапазон с использованием функции range, прежде чем продолжить вычисления, чтобы предоставить пользователю некоторую гибкость.

Я написал следующее:

# Attempt 1
function f(x,start,stop;length=1001,step=0.1)
    r=range(start,stop,length=length,step=step)
    # do more stuff with x and r
end
# error: length and step don't agree

Однако range будет принимать только одно из step или length. Он не может принимать оба, если они не определены в соглашении. Это заставляет меня захотеть определить другую функцию g, которая будет вызываться внутри f. g вызовет range и будет иметь методы для учета трех возможных сценариев ios.

  1. Пользователь указывает length при вызове f.
  2. Пользователь указывает step при вызове f.
  3. Пользователь не указывает ни length, ни step при вызове f, поэтому используется значение step по умолчанию.

Я бы предпочел не создавать больше методов f, чтобы избежать чрезмерного копирования #do more stuff with x and r. Я также хотел бы по возможности избегать операторов if, чтобы воспользоваться преимуществом множественной отправки и быть эффективным. Хотя я пока не придумал никаких решений.

Я не могу определить несколько методов g с аргументами ключевого слова, поскольку аргументы ключевого слова являются необязательными.

# Attempt 2
function g(start,stop;length=1001)
    r=range(start,stop,length=length)
end
function g(start,stop;step=0.1)
    r=range(start,stop,step=step)
end
# error: the method definitions overlap

Я также не могу преобразовать аргументы ключевого слова в обычные аргументы, потому что я не знаю, какой аргумент передать.

# Attempt 3
function g(start,stop,length)
    r=range(start,stop,length=length)
end
function g(start,stop,step)
    r=range(start,stop,step=step)
end
function f(x,start,stop;length=1001,step=0.1)
    r=g(start,stop,y)
end
# error: no way to determine y or to differentiate length from step when passed to g

1 Ответ

2 голосов
/ 08 мая 2020

Функция range использует nothing для step / length, когда они не указаны, поэтому для вас должно работать следующее:

function f(start, stop; step=nothing, length=nothing)
    if step === length === nothing
        step = 0.1 # default step
    end
    r = range(start, stop; step=step, length=length)
    return r
end

Примеры:

julia> f(1, 2; step=0.2)
1.0:0.2:2.0

julia> f(1, 2; length=3)
1.0:0.5:2.0

julia> f(1, 2) # default step
1.0:0.1:2.0

Я бы предпочел не создавать больше методов f, чтобы избежать чрезмерного копирования # do more stuff с x и r

Несколько распространенный шаблон - перемещение ядра функциональность для другой функции, например _f, и иметь несколько точек входа f, которые создают правильные аргументы для _f. Вот его набросок:

function f(x, y)
    # construct arguments with x and y
    args = ...
    return _f(args...)
end

function f(x, y, z)
    # construct arguments with x, y and z
    args = ...
    return _f(args...)
end

function _f(args...)
    # core computation
end
...