Was wäre der beste Weg, dies zu tun? %Code%? Vorlage Haskell? Etwas anderes? Ich habe noch nie eines von beiden benutzt, daher kenne ich nicht viele Details, sie zu benutzen.
Beachten Sie, dass das Programm jedes Mal kompiliert wird, wenn es ausgeführt wird. Es spielt also keine Rolle, ob ich die Zeichenfolge zum Zeitpunkt der Kompilierung oder zur Laufzeit erzeuge. Ich muss diese Zeichenkette auch in Tonnen von Stellen im Code verwenden, so dass ich es nicht wirklich "richtig" machen kann und dass es eine IO-Aktion wäre, die viel zu viel anderen Code benötigt, um in die IO-Monade eingefügt zu werden .
Die Verwendung von unsafeperformIO
in diesem speziellen Fall scheint in Ordnung zu sein, wie in der Dokumentation steht:
Damit dies sicher ist, sollte die IO-Berechnung frei von Nebenwirkungen sein und unabhängig von seiner Umgebung.
Wir sind nicht besorgt über die Reihenfolge von newStdGen
.
Ich würde nicht empfehlen, unsafePerformIO
zu verwenden. Ich nehme an, dass der Haskell-Bericht nicht besagt, dass eine konstante Funktion Memo ist, so dass es passieren kann,
gibt Ihnen unterschiedliche Ergebnisse für verschiedene Anrufe! Mit GHC wird es höchstwahrscheinlich gemerkt, aber ohne Garantien. Zum Beispiel, was ist, wenn der Compiler die Funktion einfügt? (GHC ist wahrscheinlich schlau genug, es nicht zu tun, aber wieder, keine Garantien ...). Und zum Beispiel
%Vor%wird Ihnen definitiv jedes Mal andere Ergebnisse geben, wenn es aufgerufen wird.
Ich würde lieber mit Template Haskell gehen. Es ist vielleicht ein bisschen komplizierter, aber sicher. In einem Modul definieren wir
%Vor% (Vielleicht könnte randStringD
lesbarer geschrieben werden - wenn Sie eine Idee haben, bearbeiten Sie sie bitte oder kommentieren Sie sie.)
Dann können wir es in einem anderen Modul verwenden, um eine konstante Funktion mit einem gegebenen Namen zu deklarieren:
%Vor% Ich würde nicht empfehlen, main
zu verwenden. Ich nehme an, dass der Haskell-Bericht nicht besagt, dass eine konstante Funktion Memo ist, so dass es passieren kann,
gibt Ihnen unterschiedliche Ergebnisse für verschiedene Anrufe! Mit GHC wird es höchstwahrscheinlich gemerkt, aber ohne Garantien. Zum Beispiel, was ist, wenn der Compiler die Funktion einfügt? (GHC ist wahrscheinlich schlau genug, es nicht zu tun, aber wieder, keine Garantien ...). Und zum Beispiel
%Vor%wird Ihnen definitiv jedes Mal andere Ergebnisse geben, wenn es aufgerufen wird.
Ich würde lieber mit Template Haskell gehen. Es ist vielleicht ein bisschen komplizierter, aber sicher. In einem Modul definieren wir
%Vor% (Vielleicht könnte rstr
lesbarer geschrieben werden - wenn Sie eine Idee haben, bearbeiten Sie sie bitte oder kommentieren Sie sie.)
Dann können wir es in einem anderen Modul verwenden, um eine konstante Funktion mit einem gegebenen Namen zu deklarieren:
%Vor%Was wäre der beste Weg, dies zu tun? %Code%? Vorlage Haskell? Etwas anderes? Ich habe noch nie eines von beiden benutzt, daher kenne ich nicht viele Details, sie zu benutzen.
Beachten Sie, dass das Programm jedes Mal kompiliert wird, wenn es ausgeführt wird. Es spielt also keine Rolle, ob ich die Zeichenfolge zum Zeitpunkt der Kompilierung oder zur Laufzeit erzeuge. Ich muss diese Zeichenkette auch in Tonnen von Stellen im Code verwenden, so dass ich es nicht wirklich "richtig" machen kann und dass es eine IO-Aktion wäre, die viel zu viel anderen Code benötigt, um in die IO-Monade eingefügt zu werden .
Die Verwendung von Reader
in diesem speziellen Fall scheint in Ordnung zu sein, wie in der Dokumentation steht:
Damit dies sicher ist, sollte die IO-Berechnung frei von Nebenwirkungen sein und unabhängig von seiner Umgebung.
Wir sind nicht besorgt über die Reihenfolge von Reader r a
.
Das Generieren einer Zufallszahl in MonadReader r m => m a
impliziert nicht, dass Downstream-Funktionen ask
verwenden müssen.
Hier ist eine reine Beispielfunktion, die von einem Wert vom Typ r
abhängt:
... und hier ist eine Aktion (r ->)
, die ein MonadReader r
erzeugt:
Ich muss f :: Int -> Int -> String -> Int
nicht ändern, um runReader
zu verwenden. Stattdessen verwende ich FlexibleContexts
:
Dies ist genau die Art von Problem, das Funktoren lösen sollen: das Heben von Morphismen über umbrochene Werte, so dass die Morphismen nicht modifiziert werden müssen.
Dies erzeugt eine Zeichenfolge mit zehn Zeichen Länge und nur Kleinbuchstaben. Dieser Code ist in der IO-Monade, aber str ist rein, er kann an reine Funktionen übergeben werden. Ohne die IO-Monade können Sie nichts Zufälliges bekommen. Du könntest einen unsicheren PerformIO machen, aber ich verstehe nicht warum. Sie können den Wert str übergeben, wenn Sie immer den gleichen möchten. Wenn Sie sich die letzte Zeile meines Codes anschauen, können Sie sehen, dass ich eine reine Funktion habe, die auf der Zeichenkette operiert, aber da ich sie sehen möchte, rufe ich String -> Int
auf, was eine leere IO Aktion zurückgibt.
EDIT: Oder dies könnte der Ort für die Reader Monade
sein Das Generieren einer Zufallszahl in IO
impliziert nicht, dass Downstream-Funktionen IO
verwenden müssen.
Hier ist eine reine Beispielfunktion, die von einem Wert vom Typ A
abhängt:
... und hier ist eine Aktion IO
, die ein A
erzeugt:
Ich muss f
nicht ändern, um IO
zu verwenden. Stattdessen verwende ich fmap
:
Dies ist genau die Art von Problem, das Funktoren lösen sollen: das Heben von Morphismen über umbrochene Werte, so dass die Morphismen nicht modifiziert werden müssen.
Dies erzeugt eine Zeichenfolge mit zehn Zeichen Länge und nur Kleinbuchstaben. Dieser Code ist in der IO-Monade, aber str ist rein, er kann an reine Funktionen übergeben werden. Ohne die IO-Monade können Sie nichts Zufälliges bekommen. Du könntest einen unsicheren PerformIO machen, aber ich verstehe nicht warum. Sie können den Wert str übergeben, wenn Sie immer den gleichen möchten. Wenn Sie sich die letzte Zeile meines Codes anschauen, können Sie sehen, dass ich eine reine Funktion habe, die auf der Zeichenkette operiert, aber da ich sie sehen möchte, rufe ich putStrLn
auf, was eine leere IO Aktion zurückgibt.
EDIT: Oder dies könnte der Ort für die Reader Monade
seinTags und Links haskell io template-haskell unsafe-perform-io