2010-11-28 15 views
8

¿Hay alguna manera directa en Ruby de producir una copia de un Proc?¿Cómo copio en profundidad un Proc en Ruby?

Tengo un Proc llamado @foo. Quiero otro método para aumentar periódicamente @foo con una lógica adicional. Por ejemplo:

# create initial Proc 
@foo = lambda { |x| x } 

# augment with more logic 
@foo = lambda { |x| x > 1 ? x*x : @foo[x] } 

I No quieren que la segunda línea que hace el aumento de producir una función recursiva. En cambio, quiero @foo en obligarse por el valor en el ámbito léxico de la nueva definición @foo, produciendo una función que se parece más a esto:

@foo = lambda { |x| x > 1 ? x*x : lambda{ |x| x }[x] } 

Obtengo un bucle infinito y un eventual desbordamiento de pila en su lugar, debido a la función resultante con este aspecto:

@foo = lambda { |x| x > 1 ? x*x : lambda { |x| x > 1 ? x*x : { lambda |x| # etc... 

me gustaría que el código sea así:

# augment with more logic 
@foo = lambda { |x| x > 1 ? x*x : (@foo.clone)[x] } 

pero clon no funciona en Proc.

Además, el hack estándar de copia profunda de Ruby, usando Marshal y Unmarshal, tampoco funciona en Procs. Hay alguna manera de hacer esto?

Respuesta

7

Incluso si clone funcionaría en Proc s, no le ayudaría, porque todavía estaría llamando clone en el nuevo valor de @foo, no en el anterior como usted desee.

Lo que puede hacer es almacenar el valor anterior de @foo en una variable local sobre la cual la lambda puede cerrar.

Ejemplo:

def augment_foo() 
    old_foo = @foo 
    @foo = lambda { |x| x > 1 ? x*x : old_foo[x] } 
end 

De esta manera old_foo se referirá al valor que tenían cuando @fooaugment_foo fue llamado y todo funcionará como se desea.

Cuestiones relacionadas