1

我正在制定一个框架来指定可能涉及选择的流程。我让它在每个选择都是一个岛屿的地方工作。我更喜欢子选择“分叉”父选择,以便正确考虑所有选项。

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

目前,它总是会选择“a”(它本身看起来更好)但会导致问题进一步下降。Action :one 永远不会考虑选项'b'。

我遇到过 callcc (根据我所读到的内容,不能移植到所有 Ruby 实现)和纤维(1.9 中的新功能,不能假定可用)作为可能被说服工作的东西,但我对有两个实现或者其中任何一个的黑魔法并不疯狂,真的。


我最终采取了简单的方法并将剩余的计算作为一个块传递。当我看到与现有结构的相似性时,这变得不那么痛苦了。我只是希望缩进不会脱节。

实际情况要复杂得多——有副作用,但它们包含在版本化的键值存储中。我也在列举所有可能性并选择最好的一个,所以它不能仅仅停留在成功上。

4

3 回答 3

1

您可能需要查看 [this quiz][1] 的解决方案以获取想法。

——马库斯

[1]:http ://www.rubyquiz.com/quiz70.html “这个测验”

PS 我正在去演示文稿的路上,但如果没有其他人上台,我会回来查看并提供更多信息。

于 2009-02-27T01:56:19.393 回答
1

回来,如约而至。

这里还有一些想法:

  • 您可以将选择与 yield 链接在一起,以按顺序遍历排列。换句话说,choose 可以从传递给它的选项中构建一组嵌套迭代器,它们只会让步给链中的下一个迭代器。退出封闭块会让您在收益后立即返回;如果您需要更多(例如失败原因),您可以提出和救援。
  • 三个 'r's(rescue、raise 和 retry)的时髦安排可能会做到这一点,同样的想法是,选择是嵌套选项主体或将它们嵌入到嵌套结构中。
  • 如果选项便宜且无副作用,您可能希望只考虑生成所有排列并迭代它们。
  • 如果它们不是无副作用的,您可能想尝试某种伪单子解决方案,您可以在其中懒惰地为每个排列生成 lambda。
  • 或多或少等效(但与您最初的问题相去甚远)您可能可以为它们分配一个索引(如果您可以确定每个选择的基数,则最简单,但在任何情况下都可以使用分段索引)并遍历索引.
  • 光纤已向后移植到 1.8.x

但考虑到所有因素,我认为你最好的答案是将你想要的功能包装在一个类或函数中,用 实现它callcc,然后根据需要在 this 的定义中或周围进行版本检测,以便在正确版本的红宝石。

于 2009-02-27T17:29:47.900 回答
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 回答