collect
usa n
:
# multiply each element of the data array by n def multiply(data, n) data.collect {|x| x*n } end puts multiply([1,2,3], 2) # Prints 2,4,6
n
permanece mas allá de multiplier
. Es esta característica la
que hace que la lambda doubler
sea una clausura:
# Return a lambda that retains or "closes over" the argument n def multiplier(n) lambda {|data| data.collect{|x| x*n } } end doubler = multiplier(2) # Get a lambda that knows how to double puts doubler.call([1,2,3]) # Prints 2,4,6
doubler
encapsula o clausura con la lambda el binding
de n
def accessor_pair(initialValue=nil) value = initialValue # A local variable shared by the returned lambdas. getter = lambda { value } # Return value of local variable. setter = lambda {|x| value = x } # Change value of local variable. return getter,setter # Return pair of lambdas to caller. end getX, setX = accessor_pair(0) # Create accessor lambdas for initial value 0. puts getX[] # Prints 0. Note square brackets instead of call. setX[10] # Change the value through one closure. puts getX[] # Prints 10. The change is visible through the other.
$ cat closure_shared_variables.rb # Return an array of lambdas that multiply by the arguments def multipliers(*args) # x = nil args.map {|x| lambda {|y| x*y }} end double,triple = multipliers(2,3) puts double.call(2)
$ rvm use 1.8.7 Using /Users/casiano/.rvm/gems/ruby-1.8.7-p352 $ ruby closure_shared_variables.rb 4Veamos que ocurre cuando descomentamos la línea
# x = nil
:
$ cat closure_shared_variables.rb # Return an array of lambdas that multiply by the arguments def multipliers(*args) x = nil args.map {|x| lambda {|y| x*y }} # En 1.8 la |x| es la misma x end # local double,triple = multipliers(2,3) puts double.call(2) # Prints 6 in Ruby 1.8En Ruby 1.8 la
|x|
del argumento del bloque no es local al bloque sino que
es la x
de multipliers
definida en x = nil
.
Obsérvese que la llamada multipliers(2, 3)
retorna un array con dos
lambdas.
Obtenemos así un comportamiento inesperado:
$ rvm use 1.8.7 Using /Users/casiano/.rvm/gems/ruby-1.8.7-p352 $ rvm list rvm rubies => ruby-1.8.7-p352 [ i686 ] ruby-1.9.2-head [ x86_64 ] ruby-1.9.2-p290 [ x86_64 ] ruby-1.9.3-head [ x86_64 ] $ ruby closure_shared_variables.rb 6Esto es así porque la única
x
contiene el último valor asignado a ella: 3.
En este código el problema desaparece con versiones posteriores a la 1.9 porque los argumentos de un bloque son siempre locales:
$ rvm use 1.9.2 Using /Users/casiano/.rvm/gems/ruby-1.9.2-p290 $ ruby closure_shared_variables.rb 4
Casiano Rodriguez León 2015-01-07