wenn durchfallen

7

Was ist das Haskell-äquivalente Muster für, wenn es in imperativen Sprachen durchfällt, wie:

%Vor%     
Sawyer 02.05.2014, 14:50
quelle

7 Antworten

14

Anstatt die State -Monade zu verwenden, können Sie auch die Writer -Monade verwenden und von String 's Monoid -Instanz (wirklich [a] ' s Monoid -Instanz) profitieren:

%Vor%

Was ich denke, ist ziemlich prägnant, sauber und einfach.

Ein Vorteil gegenüber der State -Monade besteht darin, dass Sie die Reihenfolge, in der Verkettungen stattfinden, neu anordnen können, indem Sie einfach die Zeilen neu anordnen. Wenn Sie also beispielsweise f 30 "test" ausführen und "atestbc" herausholen möchten, müssen Sie nur die ersten beiden Zeilen von do :

vertauschen %Vor%

Während Sie in der State monad den Vorgang ändern müssten:

%Vor%

Statt eine Beziehung zwischen der Ausführungsreihenfolge und der Reihenfolge in der Ausgabezeichenfolge zu haben, müssen Sie die tatsächlichen Operationen genau untersuchen (es gibt einen feinen Unterschied zwischen (++ "a") und ("a" ++) ), während der Writer Code sehr groß ist auf den ersten Blick meiner Meinung nach klar.

Wie @JohnL darauf hingewiesen hat, ist dies nicht gerade eine effiziente Lösung, da die Verkettung auf Haskell Strings nicht sehr schnell ist, aber Sie könnten Text und Builder ganz einfach verwenden, um dies zu umgehen:

%Vor%

Es gibt also keine wirkliche Änderung am Algorithmus außer der Umwandlung in effizientere Typen.

    
bheklilr 02.05.2014, 16:53
quelle
10

Die Funktion kann sehr knapp geschrieben werden, vorausgesetzt, wir sind bereit, die Logik der ursprünglichen imperativen Version etwas zu verschleiern:

%Vor%

Monad-Comprehensions können die ursprüngliche Logik schön reproduzieren:

%Vor%

Es handelt sich jedoch nicht um eine häufig verwendete Spracherweiterung. Zum Glück für uns (Hut Tipp zu Ørjan Johansen in den Kommentaren), gibt es bereits eingebauten Verständnis Zucker für die Liste Monade, die wir auch hier verwenden können:

%Vor%     
András Kovács 02.05.2014 15:20
quelle
6

Die Verwendung der Staatsmonade als Jan Dvoraks Kommentar suggerierte:

%Vor%     
Wyzard 02.05.2014 15:15
quelle
6

Ich denke, die kurze Antwort ist, dass der Ansatz für den Absturz in Haskell Monoids ist. Wann immer du viele Dinge zu einer Sache kombinieren willst, denke an Monoids . Zusatz ist ein großartiges Beispiel:

1 + 2 + 4 + 0 + 3 = 10.

Beim Hinzufügen von Zahlen gibt es eine Art von no-op Wert 0 . Sie können es immer hinzufügen und es wird das Ergebnis nicht ändern. Monoids verallgemeinern dieses Konzept, und Haskell nennt den no-op-Wert mempty . Auf diese Weise werden Elemente aus Ihrer Kombination entfernt (in Ihrem Beispiel fallen die Werte, die nicht gleichmäßig verteilt werden). + ist der Kombinierer. Haskell nennt es mappend . Dafür gibt es ein Kürzel: <> .

Multiplikation ist ein Monoid und der Wert mempty ist 1 , der Kombinator ist * .

Strings sind auch ein Monoid. Der mempty -Wert ist "" , der Combiner ist ++ ;

Hier ist eine sehr einfache Implementierung Ihrer Funktion mit Monoids:

%Vor%

Das Schöne daran ist, dass Monoids das Konzept verallgemeinern können, weil es ein Monoid und nicht nur eine Zeichenkette aufbaut. Sie können zum Beispiel eine Liste von Divisoren, Monoidpaaren und einem anfänglichen Monoid übergeben, und wenn der Divisor gleichmäßig verteilt wird, fügen Sie das Monoid hinzu:

%Vor%

mconcat kombiniert nur eine Liste von Monoiden.

Ihr erstes Beispiel könnte jetzt wie folgt ausgeführt werden:

%Vor%

Aber Sie könnten genauso einfach eine Nummer aufbauen:

%Vor%

Eines der großartigen Dinge an Haskell ist, dass es viele Konzepte erfasst und verallgemeinert, von denen ich nicht einmal wusste, dass sie da waren. Monoids sind wirklich praktisch, und ganze App-Architekturen können darauf gebaut werden.

    
jhickner 02.05.2014 20:42
quelle
5

Es gibt viele Möglichkeiten, dies zu tun. Eine Sache, die Sie tun könnten, ist jede if als Funktion von Int -> Maybe Char darzustellen und dann eine Liste von Maybe Char in die letzte Zeichenkette zu verketten:

%Vor%     
Lee 02.05.2014 15:03
quelle
4

IMO solltest du das komplett anders angehen. Sie testen eine Reihe sehr ähnlicher Bedingungen. diese sollten zusammen gehalten werden, nicht über eine Reihe von Bedingungen ohne offensichtliche Beziehung verteilt werden. Warum nicht in eine Liste eintragen! Da jede Mod-Option ein anderes Signalzeichen auslöst, möchten Sie eine Assoziationsliste . Du beginnst also mit [(2,'a'),(3,'b'),(5,'c')] . (Wenn es mehr davon ist, beispielsweise 10, verwende take 10 $ zip primes ['a'..] mit einer Liste aller Primzahlen!)

Nun müssen wir für jeden der Einträge entscheiden: Wenn die gegebene Zahl durch die Primzahl teilbar ist, geben Sie das Zeichen zurück, fügen Sie sonst nichts hinzu. Das ist ein sehr kurzes Listenverständnis:

%Vor%     
leftaroundabout 02.05.2014 22:08
quelle
1
%Vor%

In diesem Fall ist >>> nur flip (.) .

    
chi 02.05.2014 19:02
quelle

Tags und Links