Самоизменяющийся код в Ruby перезагрузил

Следуя моему предыдущему вопросу, позвольте мне быть более точным и менее запутанным в том, что именно я хочу. Я написал химический пакет, в котором принял решение, что названия всех химических веществ и реакций будут написаны заглавными буквами, например, "АТФ", "Аденозин", "Дезоксицитидин" и т. Д. Это позволило мне написать, например:

ATP = ChemicalSpecies.new initial_concentration: 225.0     # in micromolars
GDP = ChemicalSpecies.new initial_concentration: 75.0      # in micromolars

Теперь, если АТФ используется для фосфорилирования ВВП, используется фермент НДПК с каталитической константой

NDPK_constant = 0.6

это я хочу записать как:

ChemicalReaction.new name: ATP_GDP_phosphate_exchange,
                     rate: lambda { ATP * GDP * NDPK_constant }

Я мог бы просто написать:

ChemicalReaction.new name: ATP_GDP_phosphate_exchange,
                     reactants: [ ATP, GDP ],
                     rate: lambda { |reactant_1, reactant_2| reactant_1 * reactant_2 * NDPK_constant }

Но это кажется слишком влажным для меня. Смотри как reactant_1, reactant_2 повторить дважды, пока ATP, GDP имея в виду. Простое решение будет:

ChemicalReaction.new name: ATP_GDP_phosphate_exchange,
                     rate: lambda { _ATP * _GDP * NDPK_constant }

А также instance_eval блок определения скорости в контексте, который определяет _ATP а также _GDP как концентрации ATP, GDP, Это очень, очень близко, но не совсем то, чего я хочу, и это бесит меня. Я мог бы даже использовать RubyVM чтобы узнать, какие химикаты используются внутри блока, рассмотрите, например,.

require 'ap' # (awesome_print, like pretty_print but fancier, install if you don't have)
ap RubyVM::InstructionSequence.disassemble( lambda { _ATP * _GDP * NDPK_constant } ).split( "\n" )
#=> [ 0] "== disasm: <RubyVM::InstructionSequence:block in irb_binding@(irb)>=====",
    [ 1] "== catch table",
    [ 2] "| catch type: redo   st: 0000 ed: 0027 sp: 0000 cont: 0000",
    [ 3] "| catch type: next   st: 0000 ed: 0027 sp: 0000 cont: 0027",
    [ 4] "|------------------------------------------------------------------------",
    [ 5] "0000 trace            1                                               (  22)",
    [ 6] "0002 putself          ",
    [ 7] "0003 send             :_ATP, 0, nil, 24, <ic:0>",
    [ 8] "0009 putself          ",
    [ 9] "0010 send             :_GDP, 0, nil, 24, <ic:1>",
    [10] "0016 opt_mult         <ic:5>",
    [11] "0018 getinlinecache   25, <ic:3>",
    [12] "0021 getconstant      :NDPK_constant",
    [13] "0023 setinlinecache   <ic:3>",
    [14] "0025 opt_mult         <ic:6>",
    [15] "0027 leave

Анализируя это, вы узнаете, какие имена находятся внутри: _ATP а также _GDP, Но, как я уже сказал, из упрямства я нахожу _ATP, _GDP некрасиво. Я хочу сказать просто ATP, GDPили возможно [ATP], [GDP]потому что химики используют скобки для концентраций. Я знаю, что это то, что Юсуке Эндо называет ограниченным кодированием. У меня вопрос, можно ли победить любой из этих двух желаемых синтаксисов? Например, имея закрытие lambda { ATP * GDP * NDPK_constant }Разборка дает:

ap RubyVM::InstructionSequence.disassemble( lambda { ATP * GDP * NDPK_constant } ).split( "\n" )
#=> [ 0] "== disasm: <RubyVM::InstructionSequence:block in irb_binding@(irb)>=====",
    [ 1] "== catch table",
    [ 2] "| catch type: redo   st: 0000 ed: 0027 sp: 0000 cont: 0000",
    [ 3] "| catch type: next   st: 0000 ed: 0027 sp: 0000 cont: 0027",
    [ 4] "|------------------------------------------------------------------------",
    [ 5] "0000 trace            1                                               (  23)",
    [ 6] "0002 getinlinecache   9, <ic:0>",
    [ 7] "0005 getconstant      :ATP",
    [ 8] "0007 setinlinecache   <ic:0>",
    [ 9] "0009 getinlinecache   16, <ic:1>",
    [10] "0012 getconstant      :GDP",
    [11] "0014 setinlinecache   <ic:1>",
    [12] "0016 opt_mult         <ic:5>",
    [13] "0018 getinlinecache   25, <ic:3>",
    [14] "0021 getconstant      :NDPK_constant",
    [15] "0023 setinlinecache   <ic:3>",
    [16] "0025 opt_mult         <ic:6>",
    [17] "0027 leave 

Видно, что getconstant появились в строках 7, 10 для :ATP, :GDP, Вне блока, ATP а также GDP константы содержат ChemicalSpecies случаи, но внутри блока, я хочу, чтобы они ссылались на концентрации АТФ и ВВП. Я не нашел способа оценить блок в среде, в которой сами константы имеют разные значения (то есть, если я не хочу временно перезаписывать константы во время выполнения, используя грязные приемы, чего я не хочу). Я жажду заменить этот код RubyVM getconstant :ATP инструкция, например. send :_ATP, 0, nil, 24, <ic:0>, а затем, например. instance_eval это закрытие в среде, где _ATP средства ATP.concentration... Я знаю, что задаю сложные вопросы, извините еще раз...

Что касается второго варианта [ATP], [GDP]что для этого потребуется активировать какой-то новый хук создания массива только внутри блока, так что, если есть только один элемент, это ChemicalSpeciesего концентрация будет возвращена вместо объекта массива. Я думаю, что это одинаково трудная, если не невозможная задача.

1 ответ

Спасибо всем, и особенно Касперу. Подводя итог, я указал на Sourcify / RubyParser и сказал, чтобы изнасиловать не Ruby-код. Sourcify / RubyParser - точный ответ, который я хотел, но Каспер упомянул их только в комментариях. Что угодно - небеса берут репутацию. С тех пор, как я написал, мне пришла в голову новая идея - поддельные скобки Unicode:

ChemicalSpecies = Struct.new :concentration
ATP, GDP = ChemicalSpecies[ 225.0 ], ChemicalSpecies[ 75.0 ]
class << ( ChemicalSystem = Object.new )
  def ⁅ATP⁆; ATP.concentration end
  def ⁅GDP⁆; GDP.concentration end
end
rate = lambda { ⁅ATP⁆ + ⁅GDP⁆ * 0.6 }
ChemicalSystem.instance_exec &rate
#=> 10125.0

Поддельные скобки ⁅ATP⁆ выглядеть лучше, чем ненавистное простое решение _ATP, Есть несколько более привлекательных вариантов, таких как скобки на всю ширину [ATP]Но проблема не только в том, как их набирать, но и в том, чтобы пользователь не путал их с ванилями. Я вычеркнул весь Unicode, и единственного другого варианта, который я ненавидел, не было 「ATP, Конечно, это не имеет ничего общего с самоизменяющимся кодом; реальный ответ был в комментариях Каспера.

Другие вопросы по тегам