Use MonadRef para implementar MonadCont

Hay un problema bien conocido queno podemos usarforall tipos en elCont tipo de retorno.

Sin embargo, debería estar bien tener la siguiente definición:

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

y luego encuentre una instancia que tenga sentido. Eneste papel el autor afirmó que podemos implementarMonadFix encima deContT r m siempre quem implementadoMonadFix yMonadRef. Pero creo que si tenemos unMonadRef en realidad podemos implementarcallCC' arriba como el siguiente:

--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 = ...

(Desafortunadamente no estoy familiarizado con la semántica deshift yreset así que no proporcioné implementaciones para ellos)

Esta implementación me parece bien. Intuitivamente, cuandocallCC' siendo llamado, alimentamosk que una función que su propio efecto siempre falla (aunque no podemos proporcionar un valor de tipo arbitrariob, pero siempre podemos proporcionarmzero de tipom b y de acuerdo con la ley, debería detener efectivamente todos los efectos adicionales que se calculan), y captura el valor recibido como resultado final decallCC'.

Entonces mi pregunta es:

¿Esta implementación funciona como se espera para un idealcallCC? Podemos implementarshift yreset con la semántica adecuada también?

Además de lo anterior, quiero saber:

Para garantizar el comportamiento adecuado, debemos asumir alguna propiedad deMonadRef. Entonces, ¿cuáles serían las leyes unMonadRef tener para que la implementación anterior se comporte como se esperaba?

ACTUALIZAR

Resulta que la implementación ingenua anterior no es lo suficientemente buena. Para que satisfaga la "corriente de continuación"

callCC $\k -> k m === callCC $ const m === m

Tenemos que ajustar la implementación a

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))

En otras palabras, el originalMonadZero no es suficiente, tenemos que poder combinar unmzero valor con un cálculo normal sin cancelar todo el cálculo.

Lo anterior no responde a la pregunta, solo se ajusta ya que el intento original fue falsificado para ser candidato. Pero para la versión actualizada, las preguntas originales siguen siendo preguntas. Especialmente,reset yshift aún están por implementarse.

Respuestas a la pregunta(1)

Su respuesta a la pregunta