Im Statistics-Kurs zeigte mir unser Lehrer ein Wahrscheinlichkeitsmodell aller möglichen Würfe mit zwei Würfeln, die zu 4 addiert wurden. Wenn ich daran denke, dass die Haskell-Listen-Comprehensions ziemlich großartig sind, habe ich beschlossen, den nächsten Schritt zu machen und diesen Code zu schreiben um alle möglichen Würfe mit 4 Würfeln zu finden, die zu 10 hinzugefügt werden :
[(d1,d2,d3,d4) | d1 <- [1..6], d2 <- [1..6], d3 <- [1..6], d4 <- [1..6], (d1 + d2 + d3 + d4) == 10]
Dies funktioniert wie erwartet und gibt mir die Ausgabe von
[(1,1,2,6), (1,1,3,5), (1,1,4,4), (1,1,5,3), (1,1,6 , 2), (1,2,1,6), (1,2,2,5), (1,2,3,4), (1,2,4,3), (1,2,5 , 2), (1,2,6,1), (1,3,1,5), (1,3,2,4), (1,3,3,3), (1,3,4 , 2), (1,3,5,1), (1,4,1,4), (1,4,2,3), (1,4,3,2), (1,4,4 , 1), (1,5,1,3), (1,5,2,2), (1,5,3,1), (1,6,1,2), (1,6,2 1), (2,1,1,6), (2,1,2,5), (2,1,3,4), (2,1,4,3), (2,1,5 , 2), (2,1,6,1), (2,2,1,5), (2,2,2,4), (2,2,3,3), (2,2,4 , 2), (2,2,5,1), (2,3,1,4), (2,3,2,3), (2,3,3,2), (2,3,4 , 1), (2,4,1,3), (2,4,2,2), (2,4,3,1), (2,5,1,2), (2,5,2 , 1), (2,6,1,1), (3,1,1,5), (3,1,2,4), (3,1,3,3), (3,1,4 , 2), (3,1,5,1), (3,2,1,4), (3,2,2,3), (3,2,3,2), (3,2,4 , 1), (3,3,1,3), (3,3,2,2), (3,3,3,1), (3,4,1,2), (3,4,2 , 1), (3,5,1,1), (4,1,1,4), (4,1,2,3), (4,1,3,2), (4,1,4 , 1), (4,2,1,3), (4,2,2,2), (4,2,3,1), (4,3,1,2), (4,3,2 , 1), (4,4,1,1), (5,1,1,3), (5,1,2,2), (5,1,3,1), (5,2,1 , 2), (5,2,2,1), (5,3,1,1), (6,1,1,2), (6,1,2,1), (6,2,1 , 1)]
Hier kommt meine Frage ins Spiel. Ruby ist ein großer Teil meines Hintergrunds, also bin ich sehr groß auf der TROCKENES Prinzip. % Co_de% in meinem Code zu haben, scheint unnötig zu sein, und ich möchte glauben, dass es einen besseren Weg gibt, dies zu tun.
Wie ich es verstehe, funktioniert meine aktuelle Methode, indem ich 4 verschachtelte Schleifen hinter den Kulissen ablaufen lasse - eine für jeden Generator. Gibt es eine Möglichkeit, den einen d1 <- [1..6], d2 <- [1..6], d3 <- [1..6], d4 <- [1..6]
-Generator für alle Variablen zu verwenden, sodass effektiv 4 verschachtelte Schleifen erstellt werden? Wenn nicht, gibt es eine weniger redundante oder idiomatische Art, diesen Code zu schreiben, um das gleiche Ergebnis zu erzielen?
Hinweis: Ich bin ziemlich neu in der Sprache, also entschuldige ich mich, wenn dies etwas ist, das offensichtlich sein sollte. Wenn Sie irgendwelche Wörter / Konzepte verwenden, die einem unerfahrenen imperativ / objektorientierten Programmierer nicht geläufig sind, versuchen Sie bitte, sie für mich zu erklären.
Wenn Sie sich für die [1..6]
Wiederholung interessieren (die Fähigkeit, den Bereich unabhängig voneinander zu variieren), könnten Sie Folgendes verwenden:
Overall, um die explizite Die-Benennung zu entfernen, während dies nicht genau dasselbe ist, da es Listen statt Tupeln sein wird:
%Vor%Um die Tupel wiederherzustellen, die Sie mit dem Muster vergleichen können, die jedoch möglicherweise Probleme bei der Suche nach Fehlern mit sich bringen, wenn sich der Eingabeausdruck bei fehlgeschlagenem Mustervergleich ändert, wird das Element einfach ausgeschlossen:
%Vor% Wenn Sie bei 4-Tuples
, d. h. (1,1,3,5)
, bleiben möchten, ist das nicht wirklich elegant, aber wenn Sie bereit sind, Listen stattdessen zu verwenden, können Sie ziemlich elegant verwalten
oder mit do
-notation
edit2: Die idiomatische Möglichkeit, die Suche einzuschränken, während sie ausgeführt wird, besteht darin, möglichst früh zu testen, - so früh wie möglich, - um das zu reduzieren Suchraum so weit wie möglich:
%Vor%Das Folgende ist ein anderer Ansatz für dieses Problem.
Hier geht es darum, eine Art Netzwerk von Datenprozessoren und Multiplikatoren zu schaffen, um das Ziel zu erreichen und Möglichkeiten zur Effizienzsteigerung zu nutzen. Um Doppelarbeit zu vermeiden, verwenden wir doppelte Daten, um eine logarithmische Höhe des Prozessketten / Datenpfade-Graphen anstelle einer linearen Höhe zu erreichen.
> %Vor% Um aus all diesen Bits und Stücken eine richtige Funktion zu machen, müssen Sie herausfinden, wie Sie rn
aus n
erzeugen - indem Sie ihre Binärdarstellung verwenden, oder durch wiederholte Halbierung oder so etwas .
Für jetzt
~ & gt; foo r2
[(4,6), (5,5), (6,4)]
~ & gt; nimm 10 $ foo r4
[((1,1), (2,6)), ((1,1), (3,5)), ((1,1), (4,4)), ((1,1), (5,3)), ((1,1), (6,2)), ((1,2), (1 , (6), ((1,2), (2,5)), ((1,2), (3,4)), ((1,2), (4,3)), ((1 , 2), (5,2))]
~ & gt; nimm 10 $ foo r6
[((1, (1,1)), (1, (1,5))) ((1, (1,1)), (1, (2,4))), ((1, ( 1,1), (1, (3,3))), ((1, (1,1)), (1 , (4,2))), ((1, (1,1)), (1, (5,1))), ((1, (1,1)), (2, (1,4) )), ((1, (1,1)), (2, (2,3))), ((1, ( 1,1), (2, (3,2))), ((1, (1,1)), (2, (4,1))), ((1, (1,1)), (3, (1,3)))]
Ich glaube, dass in Haskell ein idiomatischer Weg erreicht werden kann, indem der am besten geeignete Datentyp für diesen Würfelwürfelprozess gefunden wird.
Also was ist es ..? Wir werden n
dice für m
mal rollen. Dieser Algorithmus ruft nach einem Rose-Tree-Datentyp (N-yr-Baum). Wie zum Beispiel
Nun, Sie haben dies bereits in Data.Tree
package, aber um die Logik in einfacheren Worten auszudrücken, werde ich versuchen, die oben genannten Daten sehr vereinfacht N-ary Baumtyp zu verwenden. Es ist trivial, dies mit dem Standard-Data.Tree-Paket durch Entfalten zu implementieren.
Auch das ist sehr effizient, da wir die unmöglichen Routen beseitigen, bevor sie passieren. Also keine ineffiziente Kombinatorik und Filterung hier.
%Vor%Dies berechnet einen N-stufigen Baum mit m Ebenen und jeder Pfad enthält die Würfelwerte mit Ausnahme der Wurzel (Samen), die 0 ist. Lassen Sie uns das also für 4 Würfel mit einer Zielsumme von 10 sehen.
%Vor% So oben haben wir die Baumdarstellung. Ich werde eine Funktion toList
schreiben, sobald ich etwas Zeit habe.
Tags und Links haskell list-comprehension idiomatic