Ich bin neu in der funktionalen Programmierung und habe kürzlich bei Learn You a Haskell gelernt , aber als ich dieses Kapitel durchging , blieb ich beim folgenden Programm hängen:
import Control.Monad.Writer
logNumber :: Int -> Writer [String] Int
logNumber x = Writer (x, ["Got number: " ++ show x])
multWithLog :: Writer [String] Int
multWithLog = do
a <- logNumber 3
b <- logNumber 5
return (a*b)
Ich habe diese Zeilen in einer .hs-Datei gespeichert und konnte sie nicht in mein ghci importieren, was sich beschwerte:
more1.hs:4:15:
Not in scope: data constructor `Writer'
Perhaps you meant `WriterT' (imported from Control.Monad.Writer)
Failed, modules loaded: none.
Ich habe den Typ mit dem Befehl ": info" untersucht:
Prelude Control.Monad.Writer> :info Writer
type Writer w = WriterT w Data.Functor.Identity.Identity
-- Defined in `Control.Monad.Trans.Writer.Lazy'
Aus meiner Sicht sollte dies so etwas wie "newtype Writer wa ..." sein, also bin ich verwirrt darüber, wie man den Datenkonstruktor füttert und einen Writer bekommt.
Ich denke, es könnte ein Versionsproblem sein und meine ghci-Version ist 7.4.1
Antworten:
Das Paket
Control.Monad.Writer
exportiert den Datenkonstruktor nichtWriter
. Ich denke, das war anders, als LYAH geschrieben wurde.Verwenden der MonadWriter-Typklasse in ghci
Stattdessen erstellen Sie Autoren mit der
writer
Funktion. Zum Beispiel kann ich in einer Ghci-Sitzung tunJetzt
logNumber
ist eine Funktion, die Schriftsteller erstellt. Ich kann nach seinem Typ fragen:Was mir sagt, dass der abgeleitete Typ keine Funktion ist, die einen bestimmten Writer zurückgibt , sondern alles, was die
MonadWriter
Typklasse implementiert . Ich kann es jetzt benutzen:(Eingabe tatsächlich alle in einer Zeile eingegeben). Hier habe ich den Typ angegeben, der sein
multWithLog
sollWriter [String] Int
. Jetzt kann ich es ausführen:Und Sie sehen, dass wir alle Zwischenoperationen protokollieren.
Warum ist der Code so geschrieben?
Warum überhaupt die
MonadWriter
Typklasse erstellen ? Der Grund liegt in Monadentransformatoren. Wie Sie richtig erkannt haben, ist die einfachste Art der ImplementierungWriter
ein Newtype-Wrapper über einem Paar:Sie können hierfür eine Monadeninstanz deklarieren und dann die Funktion schreiben
das protokolliert einfach seine Eingabe. Angenommen, Sie möchten eine Monade, die über Protokollierungsfunktionen verfügt, aber auch etwas anderes tut - sagen wir, sie kann auch aus einer Umgebung lesen. Sie würden dies als implementieren
Jetzt, da sich der Writer im
ReaderT
Monadentransformator befindet, können Sie die Ausgabe nicht protokollieren, da Sie sie nur verwenden könnentell w
(da dies nur bei nicht verpackten Writern funktioniert), sondern müssen sie verwendenlift $ tell w
, wodurch dietell
Funktion durch die "angehoben" wird,ReaderT
damit sie auf die zugreifen kann innere Schriftsteller Monade. Wenn Sie Transformatoren mit zwei Ebenen möchten (sagen wir, Sie möchten auch die Fehlerbehandlung hinzufügen), müssen Sie diese verwendenlift $ lift $ tell w
. Dies wird schnell unhandlich.Stattdessen können wir durch Definieren einer Typklasse jeden Monadentransformator-Wrapper um einen Writer in eine Instanz des Writers selbst verwandeln. Beispielsweise,
das heißt, wenn
w
es ein Monoid ist und einm
istMonadWriter w
, dannReaderT r m
ist es auch einMonadWriter w
. Dies bedeutet, dass wir dietell
Funktion direkt auf der transformierten Monade verwenden können, ohne uns die Mühe machen zu müssen, sie explizit durch den Monadentransformator anzuheben.quelle
mtl
dem Wechsel von Hauptversion 1. * zu 2. *, kurz nachdem LYAH und RWH geschrieben wurden. Extrem unglückliches Timing, das bei Anfängern zu viel Verwirrung führte.Control.Monad.Trans.Writer
. Neben der ArtlogNumber
istlogNumber :: (Show a, Monad m) => a -> WriterT [[Char]] m a
für mich.mtl
Bibliothek installiert (was wahrscheinlich bedeutet, dass Sie eine Basisinstallation von GHC wie minGHC anstelle der Haskell-Plattform haben). Führen Sie an einer Eingabeaufforderung auscabal update
undcabal install mtl
versuchen Sie es erneut.writer
anstelle desWriter
letzteren der Wert ctor nicht vom Modul exportiert wird, während der erstere es ist, und er kann verwendet werden, um denselben Wert zu erstellen, den Sie mit dem ctor erstellen würden, dies jedoch tut Mustervergleich nicht zulassen.Eine Funktion namens "writer" wird anstelle eines "Writer" -Konstruktors zur Verfügung gestellt. Veränderung:
logNumber x = Writer (x, ["Got number: " ++ show x])
zu:
logNumber x = writer (x, ["Got number: " ++ show x])
quelle
Ich habe eine ähnliche Nachricht erhalten, als ich die LYAH "Für ein paar Monaden mehr" mit dem Online-Haskell-Editor in ausprobiert habe repl.it ausprobiert habe
Ich habe den Import geändert von:
zu:
Mein Code sieht jetzt so aus (mit Inspiration von Kwangs Haskell-Blog ):
Code kann derzeit hier ausgeführt werden
quelle