Subsecciones


Creacion de Procs

Asociando un bloque con argumento prefijado por &

# This method creates a proc from a block
def makeproc(&p)  # Convert associated block to a Proc and store in p
  p               # Return the Proc object
end

Como retorna un Proc podemos usarlo como una suerte de constructor:

adder = makeproc {|x,y| x+y }

sum = adder.call(2,2)  # => 4


Proc.new

p = Proc.new {|x,y| x+y }

Si Proc.new es invocado sin bloque desde el interior de un método que tiene asociado un bloque entonces retorna un Proc representando al bloque asociado.

Así pues, estos dos métodos son equivalentes:

def invoke(&b)     def invoke
  b.call             Proc.new.call
end                end

Kernel.lambda

is_positive = lambda {|x| x > 0 }

Kernel.proc

En Ruby 1.9 proc es un sinónimo de Proc.new

ruby-1.9.2-head :003 > f = proc { |x| x + 1}
 => #<Proc:0x007ff03c236b60@(irb):3> 
ruby-1.9.2-head :004 > f[2]
 => 3

Lambda Literals

En el estilo clásico:

succ = lambda {|x| x+1}
En Ruby 1.9:
succ = ->(x){ x+1 }

succ.call(2)    # => 3

La lista de argumentos puede incluir la declaración de variables locales que se garantiza no sobreescribirán a las variables con el mismo nombre en el ámbito que lo contiene:

# This lambda takes 2 args and declares 3 local vars
f = ->(x,y; i,j,k) { ... }

Es posible dar valores por defecto a los argumentos:

zoom = ->(x,y,factor=2) { [x*factor, y*factor] }

Como en las declaraciones de métodos, los paréntesis son opcionales:

succ = ->x { x+1 }
f = -> x,y; i,j,k { ... }
zoom = ->x,y,factor=2 { [x*factor, y*factor] }

La lambda minimal que no toma argumentos y retorna nil vendría dada por:

->{}

Un ejemplo de expresividad:

[12] pry(main)> class Proc
[12] pry(main)*   def *(other)
[12] pry(main)*     ->(*args) { self.call(other.call(*args)) }
[12] pry(main)*   end  
[12] pry(main)* end  
=> :*
[13] pry(main)> succ = ->x{x+1}
=> #<Proc:0x007fc7a2a2f460@(pry):28 (lambda)>
[14] pry(main)> square = ->x{x*x}
=> #<Proc:0x007fc7a34df838@(pry):29 (lambda)>
[15] pry(main)> ss = succ*square
=> #<Proc:0x007fc7a349f4b8@(pry):25 (lambda)>
[17] pry(main)> ss[2]
=> 5
[18] pry(main)> ss = ->x{x+1} * ->x{x*x}
=> #<Proc:0x007fc7a3415100@(pry):25 (lambda)>
[19] pry(main)> ss[2]
=> 5

Si queremos pasar una lambda a un método que espera un bloque es necesario prefijarla de &

[21] pry(main)> data = [3,2,1,4,2]
=> [3, 2, 1, 4, 2]
[22] pry(main)> data.sort {|a,b| b-a }    # The block version
=> [4, 3, 2, 2, 1]
[23] pry(main)> data.sort &->(a,b){ b-a } # The lambda literal version
=> [4, 3, 2, 2, 1]

Casiano Rodriguez León 2015-06-18