[英]Execute remainder of ruby block more than once
I'm making a framework for specifying processes which may involve choices. 我正在建立一个框架来指定可能涉及选择的过程。 I've got it working where each choice is an island.
我可以在每个选择都是孤岛的情况下工作。 I'd prefer that subchoices 'fork' the parent choice, so that all options are properly considered.
我希望子选项“分叉”父项选择,以便正确考虑所有选项。
choose :one => lambda {
choose [a, b]
if a
raise "Illegal"
end
},
:two => ....
Currently, it would always choose 'a' (which taken by itself looks better) but causes problems further down. 目前,它总是选择“ a”(看起来更好),但会导致问题进一步恶化。 Action :one with option 'b' is never considered.
行动:永远不会考虑选项“ b”。
I've run across callcc (not portable to all Ruby implementations, from what I've read) and fibers (new in 1.9 and can't be assumed to be available) as things that might be convinced to work, but I'm not crazy about having two implementations, or about the black magic of either of them, really. 我遇到过callcc(据我所读的内容,不能移植到所有Ruby实现中)和光纤(在1.9中是新增功能,不能假定可用),可以说服它工作,但我确实对拥有两个实现或其中任何一个的黑魔法并不疯狂。
I ended up taking the easy way out and passing the remainder of the computation as a block. 我最终采取了简单的方法,将其余的计算作为一个块传递。 This became a little less painful when I saw a similarity to an existing structure.
当我看到与现有结构的相似性时,这会减轻一些痛苦。 I'm just hoping the indents don't get out of line.
我只是希望缩进不会脱节。
The real case is significantly more complicated - there are side effects, but they are contained in a versioned key-value store. 实际情况要复杂得多-有副作用,但是它们包含在版本化的键值存储中。 I'm also enumerating all possibilities and choosing the best one, so it can't just stop on success.
我还列举了所有可能性,并选择最佳的可能性,因此它不能止步于成功。
You may want to look through the solutions to [this quiz][1] for ideas. 您可能需要浏览[this quiz] [1]的解决方案以获得想法。
-- MarkusQ -MarkusQ
[1]: http://www.rubyquiz.com/quiz70.html "this quiz" [1]: http : //www.rubyquiz.com/quiz70.html “此测验”
PS I'm on my way to a presentation but I'll check back and offer more when I get back, if no one else has stepped up to the plate. PS:我正在演讲的路上,但是如果没有其他人站出来,我会再检查并提供更多信息。
Back, as promised. 像承诺的那样回来。
Here are a few more ideas: 这里还有一些想法:
But all things considered, I think your best answer would be to wrap the functionality you want in a class or function, implement it with callcc
, and then do version detection in or around the definition of this as needed so that the right implementation is used in the right version of ruby. 但是考虑到所有问题,我认为最好的答案是将所需的功能包装在类或函数中,使用
callcc
实现它,然后根据需要在此定义中或周围进行版本检测,以便使用正确的实现。在正确版本的红宝石中。
As requested, here's an example of what I meant by chaining the choices together with yields. 根据要求,这是我将选择与收益链接在一起的意思的示例。 A bare bones implementation might look something like this:
一个简单的实现可能看起来像这样:
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
And you'd use it like this (somewhat expanded from your example, to show how the parts interact): 您将像这样使用它(从您的示例中进行了扩展,以显示零件之间的交互方式):
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
Which would produce something like this (because of the print): 会产生这样的结果(由于打印):
{: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"}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.