2009-02-27 24 views
1

Ich mache ein Framework für die Festlegung von Prozessen, die Entscheidungen beinhalten können. Ich habe es funktioniert, wo jede Wahl eine Insel ist. Ich würde bevorzugen, dass die Unterauswahl "Gabel" die Elternwahl ist, so dass alle Optionen richtig berücksichtigt werden.Führen Sie den Rest des Ruby Blocks mehr als einmal

Gegenwärtig würde es immer 'a' wählen (was an sich besser aussieht), aber Probleme weiter unten verursacht. Aktion: Eine mit der Option 'b' wird nie berücksichtigt.

Ich habe über callcc (nicht tragbar zu allen Ruby-Implementierungen, von dem, was ich gelesen habe) und Fasern (neu in 1.9 und kann nicht angenommen werden, verfügbar zu sein) als Dinge, die überzeugt sein könnten, zu arbeiten, laufen aber ich bin nicht verrückt nach zwei Implementierungen oder nach der schwarzen Magie von beiden, wirklich.


Ich landete den einfachen Ausweg und übergab den Rest der Berechnung als Block. Dies wurde etwas weniger schmerzhaft, als ich eine Ähnlichkeit mit einer bestehenden Struktur sah. Ich hoffe nur, dass die Gedankenstriche nicht aus der Reihe geraten.

Der reale Fall ist wesentlich komplizierter - es gibt Nebenwirkungen, aber sie sind in einem versionierten Schlüsselwertspeicher enthalten. Ich zähle auch alle Möglichkeiten auf und wähle das Beste aus, damit es nicht einfach auf Erfolg verzichten kann.

Antwort

1

Zurück, wie versprochen.

Hier sind ein paar Ideen:

  • Sie könnten die Entscheidungen zusammen Kette mit Ausbeute ein, um Traversal der Permutationen zu tun. Mit anderen Worten, "Wählen" könnte aus den übergebenen Optionen einen Satz verschachtelter Iteratoren erstellen und diese würden dem nächsten in der Kette übergeben. Wenn Sie den geschlossenen Block verlassen, kehren Sie nach dem Ertrag zurück. Wenn Sie mehr benötigen (z. B. Fehler Gründe) könnten Sie erhöhen und retten.
  • Eine funky Anordnung der drei 'r's (Rettung, Erhöhung und Wiederholung) könnte es tun, wieder mit der Idee, dass wählen Sie die Option Bodies verschachtelt oder in eine verschachtelte Struktur einbetten.
  • Wenn die Optionen billig und nebenwirkungsfrei sind, möchten Sie vielleicht nur alle Permutationen erstellen und durchlaufen.
  • Wenn sie nicht frei von Nebenwirkungen sind, können Sie eine Pseudo-Monad-Lösung ausprobieren, bei der Sie für jede Permutation langsam Lambda-Werte erzeugen.
  • Mehr oder weniger gleichwertig (aber immer weiter von der ersten Frage entfernt) können Sie ihnen einen Index zuweisen (am einfachsten, wenn Sie die Kardinalität jeder Option bestimmen könnten, aber in jedem Fall mit einem segmentierten Index möglich) und iterieren durch die Indizes.
  • Fibers have been backported to 1.8.x

Aber alles in allem denke ich, dass die beste Antwort wäre, die Funktionalität, die Sie in einer Klasse oder Funktion wollen wickeln, implementieren sie mit callcc und dann in Versionserkennung zu tun oder um die Definition von Dies ist nach Bedarf, so dass die richtige Implementierung in der richtigen Version von Ruby verwendet wird.

+0

Ich akzeptiere das, weil es die Frage beantwortet hat, die ich gestellt habe, aber der wirkliche Fall ist wesentlich komplizierter. Ich bin ein wenig fasziniert von "Kette der Entscheidungen zusammen mit der Ausbeute"; Könntest du mich auf einen guten Artikel hinweisen? –

+0

@JustinLove Ich kann keinen Artikel finden, aber ich werde versuchen, hier am nächsten Tag ein Beispiel zu veröffentlichen. – MarkusQ

+0

@Justine Love Siehe unten zum Beispiel. – MarkusQ

1

Sie können die Lösungen für [dieses Quiz] [1] nach Ideen durchsuchen.

- MarkusQ

[1]: http://www.rubyquiz.com/quiz70.html "dieses Quiz"

P. S. Ich bin auf dem Weg zu einer Präsentation, aber ich werde zurückschauen und mehr anbieten, wenn ich zurück bin, wenn niemand sonst auf den Teller gestiegen ist.

+0

ich selbst herausfinden kann Fortsetzungen, wenn ich muß, ich hatte nur gehofft, wirklich für eine tragbare Lösung. –

+0

+1 - die Amb-Klasse sieht aus, als ob sie bereits implementiert, was Sie suchen, als ein Tropfen in Lösung. Und ich habe keinen Hinweis darauf gesehen, dass callcc veraltet ist - http://ruby-doc.org/core-1.9/classes/Continuation.html – rampion

+0

Hmm ... Ich muss einen veralteten Artikel gefunden haben. Bei einigen Implementierungen scheint es nicht unterstützt zu werden, obwohl es sich wahrscheinlich nicht um einen Deal Breaker handelt. –

1

Wie gewünscht, hier ist ein Beispiel für das, was ich meinte, indem ich die Auswahl zusammen mit den Erträgen verknüpfte. Eine nackten Knochen Implementierung könnte wie folgt aussehen:

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 

Und Sie es wie folgt verwenden würden (etwas aus Ihrem Beispiel erweitert, um zu zeigen, wie die Teile zusammenwirken):

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 

Welche produzieren würde so etwas wie dies (wegen des Drucks):

{: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"} 
+0

Hmm ... sieht aus wie Lispy Style Iteration. Sehr cool, aber in meinem Fall sind die Entscheidungen nicht einfach auf eine Datenstruktur reduzierbar. –

Verwandte Themen