1) In diesem Beispiel besteht der Zweck von ReaderT
darin, den Funktionen einen Wert vom Typ SQLiteHandle
zur Verfügung zu stellen, ohne jeder Funktion einen zusätzlichen Parameter hinzuzufügen.
2) runReaderT
"wickelt" die ReaderT
: newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a}
. Wie Sie sehen können, ist die echte Darstellung r -> m a
: eine Funktion von dem bereitgestellten Element des Typs r
zu dem m a
, von dem Sie dachten, dass Sie direkt damit zu tun hatten. So vermeidet ReaderT
nicht wirklich die Tatsache, dass ein neuer Parameter zu Ihren Funktionen hinzugefügt werden muss; es versteckt es nur für dich.
3) runReaderT ask == runReaderT $ ReaderT return == return == r -> m r
So bietet ask
Zugriff auf die "Umgebung" r
(der zusätzliche Parameter) einfach durch Einwickeln in die zugrunde liegende Monade.
Hier ist ein sehr einfaches (zugegebenermaßen zu einfach realistisches) Beispiel.
type ModeFlag = Int
g :: ModeFlag -> IO()
g modeFlag = ... -- take some action based on modeFlag
entspricht
h :: ReaderT ModeFlag IO()
h = do
modeFlag <- ask
... -- take some action based on modeFlag
Die Nützlichkeit dieser Technik nicht zu mir sofort klar war, als ich Haskell begann zu lernen. Berücksichtigen Sie jedoch den Fall, in dem Sie viele Konfigurationsparameter haben, oder Sie müssen möglicherweise bald weitere Konfigurationsparameter hinzufügen. Das Hinzufügen neuer Argumente zu Funktionen ist sehr unpraktisch. Packen Sie stattdessen einfach Ihre Konfigurationswerte in einen Datensatz und stellen Sie ihn in Ihrer gesamten Anwendung über ReaderT
bereit. Es gibt eine Funktion namens asks
, die wie ask
ist, aber auch eine Funktion für den Wert r
übernimmt. Dies kann verwendet werden, um bestimmte Felder aus einem Datensatz zu extrahieren.
data Config :: Config { param1 :: Int, param2 :: String, ... other fields }
doStuff :: ReaderT Config IO()
doStuff = do
i <- asks param1
s <- asks param2
undefined -- do some stuff
Es gibt einige weitere Beispiele für Reader
und ReaderT
in der Dokumentation (http://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Reader.html an der Unterseite), einschließlich der local
Funktion, die ziemlich cool ist, aber ich habe nicht viel verwendet.