了解Ruby中方法Proc.curry的arity参数

Understanding the arity parameter of the method Proc.curry in Ruby

Ruby 的 Proc.curry 方法在 https://ruby-doc.org/core-2.5.3/Proc.html#method-i-curry 的文档中说:

curry -> a_proc

curry(arity) -> a_proc

Returns a curried proc. If the optional arity argument is given, it determines the number of arguments. A curried proc receives some arguments. If a sufficient number of arguments are supplied, it passes the supplied arguments to the original proc and returns the result. Otherwise, returns another curried proc that takes the rest of arguments.

我知道arity是函数的参数个数。但是,我不太清楚它在这里是如何工作的。请问谁能帮忙解释一下?我已经阅读了文档中的示例,但仍然感到困惑。

也许浏览一个更好的例子可能会有所帮助。让我们从一个简单的过程开始:

p = proc { |a, b, c| "a=#{a.inspect}, b=#{b.inspect}, c=#{c.inspect}" }
p[1,2,3]
# "a=1, b=2, c=3" 

如果我们在没有 arity 参数的情况下调用 curry 那么很清楚发生了什么:

p.curry          # evaluates to a proc
p.curry[1]       # and a different proc
p.curry[1][2]    # another different proc
p.curry[1][2][3] # "a=1, b=2, c=3" 
p.curry[1,2]     # yet another proc, hooray for procs!
p.curry[1,2][3]  # "a=1, b=2, c=3"
p.curry[1,2,3]   # "a=1, b=2, c=3"

因此,p.curry 通过为参数提供值,为我们提供了一系列 Proc,直到我们有足够的值来评估原始 Proc。现在我们开始添加 arity 个值:

p.curry(1)          # some proc
p.curry(1)[]        # some other proc,
p.curry(1)[1]       # "a=1, b=nil, c=nil" 
p.curry(1)[1, 2]    # "a=1, b=2, c=nil" 
p.curry(1)[1, 2, 3] # "a=1, b=2, c=3"

p.curry(2)          # a proc
p.curry(2)[]        # another proc
p.curry(2)[1]       # oh look, a proc, a lovely surprise
p.curry(2)[1][2]    # "a=1, b=2, c=nil" 
p.curry(2)[1, 2]    # "a=1, b=2, c=nil" 
p.curry(2)[1, 2, 3] # "a=1, b=2, c=3" 

arity 参数设置柯里化过程的有效元数;不要费心看 real arity – p.curry.arity, p.curry(1).arity, ... – 因为它总是 -1 (即可变参数) .结果是 p.curry(1) 有点像

proc { |a| p[a] }.curry # "change" p's arity to 1 then curry

p.curry(2) 有点像:

proc { |a, b| p[a, b] }.curry # "change" p's arity to 2 then curry

等请记住,仅仅因为(非 lambda)proc 具有 arity n 并不意味着您必须使用 n 参数调用它。一个 proc 的数量更多的是一个建议。

当然,如果你用 lambda 尝试这种诡计,那么一切都会发生变化,因为 lambda 非常关心它们的数量:

λ = ->(a, b, c) {  "a=#{a.inspect}, b=#{b.inspect}, c=#{c.inspect}" }

λ[1]             # ArgumentError (wrong number of arguments (given 1, expected 3))
λ.curry[1]       # a lambda-proc
λ.curry[1][2][3] # "a=1, b=2, c=3" 
λ.curry[1][2, 3] # "a=1, b=2, c=3" 

λ.curry(1)       # ArgumentError (wrong number of arguments (given 1, expected 3))
λ.curry(2)       # ArgumentError (wrong number of arguments (given 2, expected 3))
λ.curry(3)       # a lambda-proc that's just like λ.curry