可以要求Julia命名参数出现吗?

时间:2016-11-05 04:54:22

标签: parameters julia keyword-argument

在Ruby中,我可以要求一个参数(1)出现,(2)有一个参数名称:

>>> def f(*, x):
...   return x + 1
... 
>>> f()
TypeError: f() missing 1 required keyword-only argument: 'x'
>>> f(3)
TypeError: f() takes 0 positional arguments but 1 was given
>>> f(x=7)
8

也就是说,我传递参数,来提供相关的参数名称。

我可以在Python中做同样的事情:

1> func f(x: Int) -> Int {return x + 1}
2> f()
error: missing argument for parameter 'x' in call
2> f(3)
error: missing argument label 'x:' in call
2> f(x:7)
$R0: Int = 8

而且,为了更好的衡量,即使Swift也能做到这一点:

X := [seq(.1*x, x = -20 .. 20)]; 
Y := [seq(y, y = -2 .. 2, .1)]; 
P := Array([seq(0, x = 0 .. 41^2-1)]);
with(plots); 
for k to 41 do for j to 41 do
slope := (1/2)*X[k]*Y[j]; 
Xp := [X[k], X[k]+.1]; Yp := [Y[j], Y[j]+0.1*slope]; 
P[41*(k-1)+j] := plot(Xp, Yp) end do end do;
display(P);

但我无法弄清楚如何在 Julia 中做到这一点。似乎关键字参数,因为它们被调用,必须采用默认参数。这是正确的,还是有办法模拟上面的Ruby和Python示例?

4 个答案:

答案 0 :(得分:6)

它可以与Ruby或Python相同的方式。事实上,它可以像

一样简单
julia> f(x, y; z=error()) = 1
f (generic function with 1 method)

julia> f(1, 2)
ERROR:
 in f(::Int64, ::Int64) at ./REPL[65]:1

但错误信息很糟糕。所以我们可以抛出一个更好的错误:

julia> f(x, y; z=throw(ArgumentError("z is required"))) = x + y + z
f (generic function with 1 method)

julia> f(1, 2)
ERROR: ArgumentError: z is required
 in f(::Int64, ::Int64) at ./REPL[25]:1

julia> f(1, 2, z=3)
6

正如oxinabox所提到的,错误是在运行时而不是编译时发现的,但这与Python或Ruby相同。

如果这太冗长,那么制作宏很容易:

macro required(ex)
    esc(Expr(:kw, ex, :(throw(ArgumentError("$($("$ex")) is required"))))
end

然后你可以做

julia> foo(x, y; @required(z), @required(w), n=4) = x + y + z + w + n
foo (generic function with 1 method)

julia> foo(1, 2)
ERROR: ArgumentError: z is required
 in foo(::Int64, ::Int64) at ./REPL[59]:1

julia> foo(1, 2, z=3)
ERROR: ArgumentError: w is required
 in (::#kw##foo)(::Array{Any,1}, ::#foo, ::Int64, ::Int64) at ./<missing>:0

julia> foo(1, 2, z=3, w=4)
14

julia> foo(1, 2, z=3, w=4, n=5)
15

这样做的原因是在没有传递参数时会计算默认参数。通过阻止成功计算默认参数,这需要用户传递参数。

答案 1 :(得分:5)

这是对的。 在julia中,您不能拥有必需的关键字参数。 关键字参数是一种特殊类型的可选参数 - 一个按名称设置,而不是按位置设置。

(与此相关:您不能按名称设置非关键字参数 - 您可以在Python和C#中执行此操作。)

你可以像@amrods建议的那样在运行时确保这一点。

我会用

做到这一点
function f(; x = nothing)
    x===nothing && error("x not set.")
    #...
end

如果调用者在编译类型中知道(推断)x的类型,那么该检查将被优化。

但直到运行时它才真正被强制执行。 您也可以使用@Fengyang very elegant way to achieve the same.

您可以在编译时通过使用生成的函数替换函数来强制执行此操作。但这是一个可怕的黑客。

答案 2 :(得分:3)

也许是由于版本漂移,这在 1.5.3 中按您的预期工作。遵循 Swift 示例:


julia> f(;x::Int64) = x + 1

julia> f()
ERROR: UndefKeywordError: keyword argument x not assigned

julia> f(3)
ERROR: MethodError: no method matching f(::Int64)

julia> f(x=3)
4

f(3) 案例中的错误消息可能需要改进。

答案 3 :(得分:2)

这会有用吗?

function f(; x = nothing)
    x + 1
end

基本上,您提供默认的初始值。

修改:将默认值设置为nothing