也许通过一个更好的例子可能会有所帮助。让我们从一个简单的过程开始:
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 通过为参数提供值给我们连续的Procs,直到我们有足够的能力评估原始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 参数设置了 curried proc 的有效数量;不要费心去看 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 具有 n 参数并不意味着您必须使用 n 参数调用它。一个 proc 的 arity 更像是一个建议。
当然,如果您尝试使用 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