前の質問に続いて、正確に何が欲しいかについて、より正確に、難読化を減らしてください。「ATP」、「アデノシン」、「デオキシシチジン」など、すべての化学物質と反応の名前を大文字にすることを決定した化学パッケージを作成しました。これにより、次のように書くことができました。
ATP = ChemicalSpecies.new initial_concentration: 225.0 # in micromolars
GDP = ChemicalSpecies.new initial_concentration: 75.0 # in micromolars
ここで、ATP を使用して 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
に、 2回繰り返しますか。簡単な解決策は次のとおりです。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]
これが、遠藤祐介が制約付きコーディングと呼ぶものであることは知っています。私の質問は、これら 2 つの望ましい構文のいずれかを打ち負かすことができるかということです。たとえば、クロージャが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
、 の 7 行目、getconstant
10 行目に表示されていることがわかります。ブロックの外では定数にインスタンスが含まれていますが、ブロック内では ATP と GDP の濃度を参照するようにします。定数自体が異なる意味を持つ環境でブロックを評価する方法が見つかりませんでした (つまり、実行時に汚いトリックを使用して一時的に定数を書き換えたい場合を除きます)。私が切望しているのは、このRubyVMコード命令をたとえば. 、そして例えば。環境でのこの閉鎖は...難しい質問をしていることを知っています、もう一度申し訳ありません...:ATP
:GDP
ATP
GDP
ChemicalSpecies
getconstant :ATP
send :_ATP, 0, nil, 24, <ic:0>
instance_eval
_ATP
ATP.concentration
2 番目のオプション については[ATP]
、[GDP]
ブロック内のみで何らかの新しい配列作成フックをアクティブにする必要があるため、要素が 1 つしかない場合、つまり がありChemicalSpecies
、配列オブジェクトの代わりにその濃度が返されます。不可能ではないにしても、これは同じくらい難しいと思います。