2009-02-27 99 views
1

我正在制定一個框架來指定可能涉及選擇的過程。我已經在每個選擇都是島嶼的地方工作。我更希望子選擇'分叉'父母選擇,以便適當考慮所有選項。不止一次執行紅寶石塊的其餘部分

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

目前,它總會選擇'a'(本身看起來更好),但會導致問題進一步惡化。行動:一個選項'b'是從來沒有考慮。

我已經運行了callcc(不能移植到所有Ruby實現,從我讀過的)和纖維(新的1.9並且不能被認爲是可用的),作爲可能被確信工作的東西,但我對兩種實現方式或者其中任何一種的黑魔法都不是很滿意。


我最終選擇了簡單的方法,並將其餘的計算作爲一個塊傳遞。當我看到與現有結構相似時,這變得不那麼痛苦。我只是希望縮進不會脫節。

真實情況明顯更復雜 - 存在副作用,但它們包含在版本化的鍵值存儲中。我也列舉了所有的可能性並選擇了最好的,所以它不能停止成功。

回答

1

返回,如承諾。

這裏有一些更多的想法:

  • 你可以鏈的選擇與產量在一起,在排列順序遍歷做的。換句話說,select可以從傳遞給它的選項中構建一組嵌套的迭代器,並且它們只會屈服於鏈中的下一個迭代器。退出封閉區塊會讓您回到收益率之後;如果您需要更多(例如失敗的原因),您可以籌集和救援。
  • 三個'r's(救援,提高和重試)的時髦安排可能會做到這一點,同樣的想法是,選擇是嵌套選項主體或將它們嵌入到嵌套結構中。
  • 如果這些選項很便宜且無副作用,您可能需要查看產生所有排列並遍歷它們。
  • 如果他們沒有副作用,你可能想嘗試某種僞單體解決方案,在那裏你懶散地爲每個排列生成lambda表達式。
  • 或多或少等價(但偏離最初的問題越遠),您可能可以爲它們指定一個索引(如果您可以確定每個選項的基數,但在任何情況下都可以使用分段索引,則最容易)並重復通過索引。
  • Fibers have been backported to 1.8.x

但是考慮所有的事情,我想你最好的答案是包你在一個類或函數想要的功能,與callcc實現它,然後做版本檢測或周圍的定義這是根據需要的,以便在正確的Ruby版本中使用正確的實現。

1

你可能想看看[這個測驗] [1]的想法的解決方案。

- MarkusQ

[1]:http://www.rubyquiz.com/quiz70.html 「此測驗」

P.S.我正在去演示的路上,但當我回來的時候,如果沒有其他人加入,我會回頭查看並提供更多信息。

+0

我可以自己找出延續,如果我必須,我只是真的希望有一個更便攜的解決方案。 – 2009-02-27 02:47:35

+0

+1 - Amb類似乎已經實現了您尋找的解決方案。我沒有看到callcc被棄用的跡象 - http://ruby-doc.org/core-1.9/classes/Continuation.html – rampion 2009-02-27 02:56:32

+0

嗯...我必須擊中一篇過時的文章。它似乎在某些實現上不受支持,但可能不是交易斷路器。 – 2009-02-27 03:36:12

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"}