Ich habe gerade die Definition der Klasse verstanden MonadReader
class Monad m => MonadReader r m | m -> r where
...
Nachdem ich das Dokument der funktionalen Abhängigkeit in Haskell gelesen habe, kann ich jetzt verstehen, dass | m -> r
angegeben wird, dass die Typvariable r
eindeutig von bestimmt wird m
. Ich denke, diese Anforderung ist vernünftig, basierend auf den wenigen typischen Instanzen von MonadReader, die ich bisher gesehen habe (z. B. Reader
), aber es scheint mir, dass wir Instanzen wie Reader
auch ohne diese funktionale Abhängigkeitsklausel definieren können .
Meine Frage ist, warum wir bei der Definition von MonadReader eine funktionale Abhängigkeit benötigen. Ist dies funktional erforderlich, um MonadReader in einem Sinne zu definieren, dass MonadReader ohne MonadReader nicht ordnungsgemäß definiert werden kann, oder ist es lediglich eine Einschränkung, die Verwendungsmöglichkeiten von MonadReader einzuschränken, damit sich die Instanzen von MonadReader alle auf eine bestimmte erwartete Weise verhalten?
quelle
MonadReader
; es wird für die bequeme Verwendung benötigtMonadReader
.Antworten:
Es ist erforderlich, dass die Typinferenz auf eine Weise funktioniert, die für den Benutzer bequemer ist.
Ohne den Fundep würde dies beispielsweise nicht kompiliert werden:
Um die obige Kompilierung zu machen, müssten wir schreiben
Dies liegt daran, dass der Compiler ohne fundep nicht darauf schließen kann, dass
x
es sich um eine handeltInt
. Schließlich kann eine MonadeReadertT Int IO
mehrere Instanzen habenDaher muss der Programmierer eine Anmerkung bereitstellen, die erzwingt
x :: Int
, oder der Code ist mehrdeutig.quelle
Dies ist keine wirkliche Antwort, aber für einen Kommentar viel zu lang. Sie haben
MonadReader
Recht, dass es möglich ist, die Klasse ohne Fundep zu definieren . Insbesondere bestimmt die Typensignatur jeder Methode jeden Klassenparameter. Es wäre durchaus möglich, eine feinere Hierarchie zu definieren.Das Hauptproblem bei diesem Ansatz besteht darin, dass Benutzer eine Reihe von Instanzen schreiben müssen.
quelle
Ich denke, die Quelle der Verwirrung ist die in der Definition von
Es wird implizit angenommen, dass es sich selbst
m
enthältr
(für häufige Fälle). Lassen Sie mich eine leichtere Definition vonReader
as verwendenWenn der
r
Parameter ausgewählt ist, können Sie einfach eine Monadeninstanz für definierenReader r
. Das bedeutet, dass in der Typklasse die Definition ersetzt werdenm
sollteReader r
. Schauen Sie sich also an, wie der Ausdruck endet:Aber warum brauchen wir das? Schauen Sie sich die Definition
ask
innerhalb derMonadReader
Klasse an.Ohne die fun-dep könnte mich nichts daran hindern,
ask
einen anderen Typ als Zustand zurückzugeben. Darüber hinaus konnte ich viele Instanzen von Monadenlesern für meinen Typ definieren. Dies wären beispielsweise gültige Definitionen ohne func-depWenn ich also einen Wert
val :: ReaderT Int IO Double
hätte, was wäre das Ergebnis vonask
. Wir müssten eine Typensignatur wie unten angebenAbgesehen davon, dass es sinnlos ist, ist es nicht überzeugend, den Typ immer wieder zu spezifizieren.
Als Schlussfolgerung unter Verwendung der tatsächlichen Definition von
ReaderT
. Wenn Sie so etwas wie habenval :: ReaderT String IO Int
die funktionale Abhängigkeit sagt solche Art könnte nur eine einzige Instanz habenMonadReader
typeclass , die derjenige, der Verwendungen sein definiert istString
alsr
quelle