Verwenden Sie MonadRef, um MonadCont zu implementieren
Es gibt ein bekanntes Problem, daswir können nicht verwendenforall
tippt die einCont
Rückgabetyp.
Es sollte jedoch in Ordnung sein, die folgende Definition zu haben:
class Monad m => MonadCont' m where
callCC' :: ((a -> forall b. m b) -> m a) -> m a
shift :: (forall r.(a -> m r) -> m r) -> m a
reset :: m a -> m a
und dann finden Sie eine Instanz, die Sinn macht. Imdieses Papier Der Autor behauptete, dass wir implementieren könnenMonadFix
aufContT r m
vorausgesetzt, dassm
umgesetztMonadFix
undMonadRef
. Aber ich denke, wenn wir eine habenMonadRef
wir können tatsächlich umsetzencallCC'
oben wie folgt:
--satisfy law: mzero >>= f === mzero
class Monad m => MonadZero m where
mzero :: m a
instance (MonadZero m, MonadRef r m) => MonadCont' m where
callCC' k = do
ref <- newRef Nothing
v <- k (\a -> writeRef ref (Just a) >> mzero)
r <- readRef ref
return $ maybe v id r
shift = ...
reset = ...
(Leider kenne ich mich mit der Semantik von nicht ausshift
undreset
deshalb habe ich keine Implementierungen für sie bereitgestellt)
Diese Implementierung scheint für mich in Ordnung zu sein. Intuitiv, wanncallCC'
gerufen werden, füttern wirk
Wobei eine Funktion, die ihre eigene Wirkung hat, immer fehlschlägt (obwohl wir keinen willkürlichen Wert liefern können)b
, aber wir können immer zur Verfügung stellenmzero
vom Typm b
und laut Gesetz sollte es effektiv verhindern, dass weitere Effekte berechnet werden, und es erfasst den empfangenen Wert als Endergebnis voncallCC'
.
Meine Frage lautet also:
Funktioniert diese Implementierung erwartungsgemäß für ein Ideal?callCC
? Können wir umsetzenshift
undreset
auch mit der richtigen Semantik?
Zusätzlich zu den oben genannten möchte ich wissen:
Um das richtige Verhalten zu gewährleisten, müssen wir einige Eigenschaften von annehmenMonadRef
. Also, was würden die Gesetze einMonadRef
muss, damit sich die obige Implementierung wie erwartet verhält?
AKTUALISIEREN
Es stellt sich heraus, dass die obige naive Implementierung nicht gut genug ist. Damit es "Fortsetzung aktuell" erfüllt
callCC $\k -> k m === callCC $ const m === m
Wir müssen die Umsetzung anpassen auf
instance (MonadPlus m, MonadRef r m) => MonadCont' m where
callCC' k = do
ref <- newRef mzero
mplus (k $ \a -> writeRef ref (return a) >> mzero) (join (readRef ref))
Mit anderen Worten, das OriginalMonadZero
ist nicht genug, wir müssen in der Lage sein, a zu kombinierenmzero
Wert bei einer normalen Berechnung, ohne die gesamte Berechnung abzubrechen.
Das Obige beantwortet die Frage nicht, es wird nur angepasst, da der ursprüngliche Versuch als Kandidat verfälscht wurde. Für die aktualisierte Version sind die ursprünglichen Fragen jedoch noch Fragen. Insbesondere,reset
undshift
sind noch zu implementieren.