Pregunta

Estoy haciendo un marco de procesos que pueden implicar decisiones especificando. Tengo que trabaja en cada elección es una isla. Yo prefiero que subchoices 'tenedor' la elección de los padres, por lo que todas las opciones se consideran adecuadamente.

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

Actualmente, seguro que elegiría 'a' (que toma por sí se ve mejor) pero causa problemas más abajo. Acción:. Una con la opción 'b' no se considera

Me he encontrado a través de callcc (no portátil para todas las implementaciones de Ruby, por lo que he leído) y fibras (nuevo en 1.9 y no se puede suponer que esté disponible) como cosas que podrían ser convencidos de que trabajar, pero no estoy loco por tener dos implementaciones, o sobre la magia negro de cualquiera de ellos, de verdad.


terminé tomando el camino más fácil y pasar el resto de la computación como un bloque. Esto se convirtió en un poco menos dolorosa cuando vi una semejanza a una estructura existente. Sólo estoy esperando que los guiones no se salgan de la línea.

El caso real es mucho más complicado - hay efectos secundarios, pero que están contenidas en un almacén de claves-valor de versión. También estoy enumerando todas las posibilidades y elegir la mejor, así que no puedo parar en caso de éxito.

¿Fue útil?

Solución

Volver, como se había prometido.

Aquí están algunas ideas más:

  • Usted puede encadenar las opciones junto con el rendimiento de hacer un recorrido con el fin de las permutaciones. En otras palabras, eligen podría construir un conjunto de iteradores anidados de las opciones que se le pasan, y que simplemente ceder el paso a la siguiente en la cadena. Al salir del bloque cerrado que pone la derecha de nuevo después de que el rendimiento; si necesita más (por ejemplo razones de fallo) se podía levantar y rescate.
  • Un arreglo moderno de los tres 'de r (rescate, elevar, y vuelva a intentar) podría hacerlo, de nuevo con la idea de que elija se anidan los cuerpos de opción o incrustarlos en una estructura anidada.
  • Si las opciones son baratos y libre de efectos secundarios, puede que desee mirar simplemente la producción de todas las permutaciones y iteración a través de ellos.
  • Si son efecto no lado libre, es posible que quieran probar algún tipo de solución pseudo-mónada, donde perezosamente producir lambdas para cada permutación.
  • Más o menos equivalente (pero descarriados cada vez más lejos de su pregunta inicial) es posible que pueda asignarles un índice (más fácil si se pudiera determinar la cardinalidad de cada elección, pero es posible con un índice segmentado en cualquier caso) y iterate a través de los índices.
  • fibras se han portado a 1.8.x

Pero a fin de cuentas, creo que la mejor respuesta sería envolver la funcionalidad que desea en una clase o función, aplicar con callcc , y luego hacer la detección de versiones en o alrededor de la definición de este como sea necesario para que la implementación derecha se utiliza en la versión correcta de rubí.

Otros consejos

Es posible que desee mirar a través de las soluciones a [esta prueba] [1] para las ideas.

- MarkusQ

[1]: http://www.rubyquiz.com/quiz70.html "esta prueba"

P.S. Estoy en mi camino a una presentación, pero voy a ver hacia atrás y ofrecen más cuando regrese, si nadie más ha intensificado a la placa.

Conforme a lo solicitado, he aquí un ejemplo de lo que quiero decir por el encadenamiento de las opciones junto con los rendimientos. Una aplicación esqueleto podría ser algo como esto:

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

Y que tendría que utilizar como este (algo ampliada de su ejemplo, para mostrar cómo interactúan las partes):

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

que produciría algo como esto (debido a la impresión):

{: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"}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top