Следуя моему предыдущему вопросу, позвольте мне быть более точным и менее запутанным в отношении того, что именно я хочу. Я написал химический пакет, в котором решил, что названия всех химических веществ и реакций будут писаться с большой буквы, например, «АТФ», «Аденозин», «Деоксицитидин» и т. д. Это позволило мне написать, например:
ATP = ChemicalSpecies.new initial_concentration: 225.0 # in micromolars
GDP = ChemicalSpecies.new initial_concentration: 75.0 # in micromolars
Теперь, если АТФ используется для фосфорилирования GDP с использованием фермента NDPK с каталитической константой
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 code getconstant :ATP
, например. send :_ATP, 0, nil, 24, <ic:0>
, а затем, например. instance_eval
это замыкание в среде, где _ATP
означает ATP.concentration
... Я знаю, что задаю трудные вопросы, еще раз извините...
Что касается второго варианта [ATP]
, [GDP]
, то для этого потребуется активировать какой-то новый хук создания массива только внутри блока, чтобы, если есть только один элемент, то есть ChemicalSpecies
, возвращалась его концентрация вместо объекта массива . Я думаю, что это столь же сложная, если не невыполнимая задача.
eval
может даже помочь. т.е. замените[ATP]
наATP.concetration
иeval
целиком. - person Casper   schedule 02.02.2013