1

選択を伴う可能性のあるプロセスを指定するためのフレームワークを作成しています。それぞれの選択肢が島である場合、私はそれを機能させています。すべてのオプションが適切に考慮されるように、サブチョイスが親の選択肢を「フォーク」することをお勧めします。

choose :one => lambda {
    choose [a, b]
    if a
      raise "Illegal"
    end
  },
  :two => ....

現在、常に「a」(それ自体の方が見栄えが良い)を選択しますが、さらに下の方で問題が発生します。アクション:オプション'b'のあるものは考慮されません。

私はcallcc(私が読んだものからすべてのRuby実装に移植可能ではない)とファイバー(1.9で新しく、利用可能であるとは想定できない)に出くわしましたが、私は動作すると確信できるかもしれません。実際には、2つの実装があることや、どちらかの黒魔術に夢中ではありません。


簡単な方法で、残りの計算をブロックとして渡すことになりました。既存の構造との類似性を見たとき、これは少し痛みが少なくなりました。インデントがずれないことを願っています。

実際のケースは非常に複雑です。副作用がありますが、それらはバージョン管理されたKey-Valueストアに含まれています。また、すべての可能性を列挙し、最適なものを選択しているので、成功を止めることはできません。

4

3 に答える 3

1

[このクイズ][1] の解決策を調べてアイデアを得ることができます。

-- マーカスQ

[1]: http://www.rubyquiz.com/quiz70.html「このクイズ」

PS プレゼンテーションに向かっていますが、他の誰もプレートにステップアップしていない場合は、戻ってきたときに確認してより多くのことを提供します.

于 2009-02-27T01:56:19.393 に答える
1

リクエストに応じて、選択肢を利回りと連鎖させることで私が意味したことの例を次に示します。必要最小限の実装は次のようになります。

def choose_one_of_each(choices,results,&block)
    if choices.empty?
        yield results
      else
        c = choices.dup
        var,val = c.shift
        choose(val) { |v|
            choose_one_of_each(c,results.update(var => v),&block)
            }
      end
    end

def choose(options,&block)
    case options
      when Hash  then choose_one_of_each options,{},&block
      when Range then options.each { |item| yield item rescue nil }
      else            options.each { |item| yield item rescue nil }
      end
    end

そして、次のように使用します(パーツがどのように相互作用するかを示すために、例からいくらか拡張されています):

a = 7
b = 'frog'
choose(
    :one => [a,b], 
    :two => ['stay','go','punt'], 
    :three => {:how => ['in the car','in a boat','by magic'],:how_fast => 0..2 }
  ) do |choices|
     raise "illegal" if choices[:one] == a
     raise "You can't stay fast!" if choices[:two] == 'stay' and choices[:three][:how_fast] > 0
     raise "You go that slow!"    if choices[:two] == 'go'   and choices[:three][:how_fast] < 1
     print choices.inspect,"\n"
     end

これは次のようなものを生成します(印刷のため):

{:three=>{:how=>"in the car", :how_fast=>0}, :one=>"frog", :two=>"stay"}
{:three=>{:how=>"in the car", :how_fast=>0}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"in the car", :how_fast=>1}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"in the car", :how_fast=>1}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"in the car", :how_fast=>2}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"in the car", :how_fast=>2}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"in a boat", :how_fast=>0}, :one=>"frog", :two=>"stay"}
{:three=>{:how=>"in a boat", :how_fast=>0}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"in a boat", :how_fast=>1}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"in a boat", :how_fast=>1}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"in a boat", :how_fast=>2}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"in a boat", :how_fast=>2}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"by magic", :how_fast=>0}, :one=>"frog", :two=>"stay"}
{:three=>{:how=>"by magic", :how_fast=>0}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"by magic", :how_fast=>1}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"by magic", :how_fast=>1}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"by magic", :how_fast=>2}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"by magic", :how_fast=>2}, :one=>"frog", :two=>"punt"}
于 2009-03-07T22:58:06.483 に答える
1

約束通り、帰ります。

さらにいくつかのアイデアを次に示します。

  • 選択を yield と一緒に連鎖させて、順列を順番にトラバーサルすることができます。つまり、choose は、渡されたオプションから一連のネストされたイテレータを構築でき、それらはチェーン内の次のイテレータに渡されます。囲まれたブロックを終了すると、yield の直後に戻ります。さらに必要な場合 (失敗の理由など)、レイズとレスキューを行うことができます。
  • 3 つの 'r' (rescue、raise、および retry) のファンキーな配置がそれを行う可能性があります。これも、choose がオプション本体をネストするか、ネストされた構造に埋め込むという考えで行われます。
  • オプションが安価で副作用がない場合は、すべての順列を生成してそれらを反復処理することを検討することをお勧めします。
  • 副作用がない場合は、順列ごとにラムダを遅延して生成する、ある種の疑似モナド ソリューションを試してみることをお勧めします。
  • 多かれ少なかれ同等(ただし、最初の質問から遠く離れています)、それらにインデックスを割り当てることができる場合があります(各選択肢のカーディナリティを判断できれば最も簡単ですが、いずれにしてもセグメント化されたインデックスで可能です)、インデックスを反復処理します.
  • ファイバーは 1.8.x にバックポートされました

しかし、すべてを考慮すると、必要な機能をクラスまたは関数にラップし、 で実装しcallcc、必要に応じて this の定義内またはその周辺でバージョン検出を行い、適切な実装が使用されるようにするのが最善の答えだと思いますruby の正しいバージョン。

于 2009-02-27T17:29:47.900 に答える