Pregunta

Joe Van Dyk preguntó la lista de correo de Ruby:

Hola,

En Ruby, supongo que no se puede ordenar un objeto lambda/proc, ¿verdad?¿Es eso posible en Lisp u otros idiomas?

Lo que estaba tratando de hacer:

l = lamda { ... }
Bj.submit "/path/to/ruby/program", :stdin => Marshal.dump(l)

Por lo tanto, estoy enviando a Backgroundjob un objeto Lambda, que contiene el contexto/código para qué hacer.Pero supongo que eso no fue posible.Terminé organizando un objeto Ruby normal que contenía instrucciones sobre qué hacer después de que se ejecutara el programa.

José

¿Fue útil?

Solución

No se puede ordenar un Lambda o Proc.Esto se debe a que ambos se consideran cierres, lo que significa que se cierran alrededor de la memoria en la que fueron definidos y pueden hacer referencia a ella.(Para ordenarlos, tendría que ordenar toda la memoria a la que podían acceder en el momento en que fueron creados).

Sin embargo, como señaló Gaius, puedes usar rubí2rubí para conseguir la cadena del programa.Es decir, puede ordenar la cadena que representa el código Ruby y luego reevaluarla más tarde.

Otros consejos

También puedes ingresar tu código como una cadena:

code = %{
    lambda {"hello ruby code".split(" ").each{|e| puts e + "!"}}
}

luego ejecútelo con eval

eval code

que devolverá un Ruby Lamda.

utilizando el %{} El formato escapa de una cadena, pero solo se cierra con una llave no coincidente.es decir.puedes anidar llaves como esta %{ [] {} } y todavía está cerrado.

la mayoría de los resaltadores de sintaxis de texto no se dan cuenta de que se trata de una cadena, por lo que aún muestran el resaltado de código normal.

Si está interesado en obtener una versión en cadena del código Ruby usando Ruby2Ruby, es posible que le interese este hilo.

Intentar rubí2rubí

He encontrado que proc_to_ast hace el mejor trabajo: https://github.com/joker1007/proc_to_ast.

Funciona con seguridad en Ruby 2+, y he creado un PR para la compatibilidad con Ruby 1.9.3+ (https://github.com/joker1007/proc_to_ast/pull/3)

Si proc está definido en un archivo, U puede obtener la ubicación del archivo de proc, luego serializarlo y luego, después de deserializarlo, usar la ubicación para volver al proc nuevamente.

proc_location_array = proc.source_location

después de deserializar:

nombre_archivo = proc_location_array[0]

número_línea = proc_location_array[1]

proc_line_code = IO.readlines(nombre_archivo)[número_línea - 1]

proc_hash_string = proc_line_code[proc_line_code.index("{")..proc_line_code.length]

proc = eval("lambda #{proc_hash_string}")

Érase una vez, esto era posible usando la gema interna de rubí (https://github.com/cout/ruby-internal), p.ej.:

p = proc { 1 + 1 }    #=> #<Proc>
s = Marshal.dump(p)   #=> #<String>
u = Marshal.load(s)   #=> #<UnboundProc>
p2 = u.bind(binding)  #=> #<Proc>
p2.call()             #=> 2

Hay algunas salvedades, pero han pasado muchos años y no puedo recordar los detalles.Como ejemplo, no estoy seguro de qué sucede si una variable es un dynvar en el enlace donde se vuelca y un local en el enlace donde se vuelve a enlazar.Serializar un AST (en MRI) o un código de bytes (en YARV) no es trivial.

El código anterior funciona en YARV (hasta 1.9.3) y MRI (hasta 1.8.7).No hay ninguna razón por la que no se pueda hacer que funcione en Ruby 2.x, con un poco de esfuerzo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top