也许通过一个更好的例子可能会有所帮助。让我们从一个简单的过程开始:
p = proc { |a, b, c| "a=#{a.inspect}, b=#{b.inspect}, c=#{c.inspect}" }
p[1,2,3]
# "a=1, b=2, c=3"
如果我们curry
在没有arity
参数的情况下调用,那么很清楚发生了什么:
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
s,直到我们有足够的值来评估原始 s 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 的有效参数;不要费心去看真正的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 具有 arityn
并不意味着您必须使用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