问题
I am concerned about writing self-modifying code in Ruby. And by self-modifying, I mean being able to write functions that take a code block as an input value, and output another code block based on this. (I am not asking about basics such as redefining methods at runtime.)
What I might want to do is, for example, having the following block,
_x_ = lambda { |a, b, c, d| b + c }
one can notice that arguments a
and d
are not used in the body at all, so I would like a function eg. #strip
to remove them,
x = _x_.strip
which should produce same result as writing:
x = lambda { |b, c| b + c }
Now in Lisp, this would be easy, since Lisp code is easily manipulable data. But I do not know how to manipulate Ruby code. I can parse it eg. by
RubyVM::InstructionSequence.disassemble( x )
But how, based on this, do I write a modified block? Other examples of what I would want to do are are eg.
y = lambda { A + B }
y.deconstantize
# should give block same as saying
lambda { |_A, _B| _A + _B }
So far, in Ruby, I have never encountered a situation where I had to concede that something is not possible. But this time, gut feeling tells me that I might have encountered the fundamental weakness of beautifully structured code vs. code with little syntax to speak about (which would be Lisp). Please enlighten me.
回答1:
Boris do you necessarily have to rely on Ruby to begin with here?
Why not just create your own situation-specific language that the chemists can use just for the purpose to express their formulas in the most convenient way. Then you create a simple parser and compiler for this "chemical expression language".
What I mean is this parser and compiler will parse and compile the expressions the chemists write in their Ruby code. Then you could have:
ChemicalReaction.new(..., "[ATP] * [GDP] * NDPK_constant")
Voila: ultimate flexibility.
That's the approach I would take if usability is your main concern. Already writing out "lambda" seems like an unnecessarily cumbersome thing to me here, if all you want to do is express some domain-specific formula in the most compact way possible.
回答2:
Detecting whether a block variable is used or not is a complicated task, and you seem to be saying that you can do that by using RubyVM
. So the question seems to be asking how to change the arity of the code.
If you have:
_x_ = ->a, b, c, d{b + c}
and suppose you were able to use RubyVM
and come to know that a
and d
are not used, so you want to create
x = ->b, c{b + c}
out of _x_
. Then, that is simple:
x = ->b, c{_x_.call(nil, b, c, nil)}
来源:https://stackoverflow.com/questions/14658230/self-modifying-code-in-ruby