2009-07-07 9 views

Antwort

5

Also hier ist, wie mit Blöcken zu tun currying, anstatt Methoden:

def curry(&block) 
    arity = (block.arity >= 0) ? block.arity : -(block.arity + 1) 
    # return an immediate value if the block has one 
    return block[] if arity == 0 

    # otherwise, curry it argument by argument 
    args = [] 
    innermost = lambda do |last,*extra| 
    args[arity-1] = last 
    block[*(args+extra)] 
    end 
    (0...(arity-1)).to_a.reverse.inject(innermost) do |inner,i| 
    lambda do |arg_i,*extra| 
     args[i] = arg_i 
     # pass extra arguments on to inner calls 
     if extra.empty? 
     inner 
     else 
     inner[*extra] 
     end 
    end 
    end 
end 

Und es funktioniert ziemlich gut in der Praxis. Argumente können curried werden oder nicht, und zusätzliche Argumente werden wie üblich gesammelt:

irb> (curry { |x,y| x + y })[1,2] 
#=> 3 
irb> (curry { |x,y| x + y })[1][2] 
#=> 3 
irb> (curry { |x,*ys| ys << x })[1] 
#=> [1] 
irb> (curry { |x,*ys| ys << x })[1,2,3] 
#=> [2, 3, 1] 
irb> (curry { |x,y,*zs| zs << (x+y) })[1,2] 
#=> [3] 
irb> (curry { |x,y,*zs| zs << (x+y) })[1,2,4] 
#=> [4, 3] 
irb> (curry { |x,y,*zs| zs << (x+y) })[1][2] 
#=> [3] 
irb> (curry { |x,y,*zs| zs << (x+y) })[1][2,4] 
#=> [4, 3] 
irb> (curry { |a,b,c,d,e| a+b+c+d+e })[1,2,3,4,5] 
#=> 15 
irb> (curry { |a,b,c,d,e| a+b+c+d+e })[1][2][3][4][5] 
#=> 15 
irb> (curry { |a,b,c,d,e| a+b+c+d+e })[1,2][3][4][5] 
#=> 15 
irb> (curry { |a,b,c,d,e| a+b+c+d+e })[1][2,3,4][5] 
#=> 15 

ich die Design-Entscheidung keine argument Blöcke zurückkehren einen unmittelbaren Wert zu haben, machte auf currying:

irb> curry { 3 } 
#=> 3 
irb> curry { |*xs| xs } 
#=> [] 

Dies ist notwendig, um zu vermeiden, mit einer [] jedes Mal zu beenden Currying (und ist ziemlich Haskell-like).