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.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage