Use o MonadRef para implementar o MonadCont

Existe um problema bem conhecido quenão podemos usarforall tipos noCont tipo de retorno.

No entanto, deve ser bom ter a seguinte definição:

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

e, em seguida, encontre uma instância que faça sentido. Noeste papel o autor afirmou que podemos implementarMonadFix Em cima deContT r m fornecendom implementadoMonadFix eMonadRef. Mas acho que se tivermos umMonadRef nós podemos realmente implementarcallCC' acima como o seguinte:

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

(Infelizmente não estou familiarizado com a semântica deshift ereset então não forneço implementações para eles)

Esta implementação parece boa para mim. Intuitivamente, quandocallCC' sendo chamado, nós alimentamosk qual função que seu próprio efeito sempre falha (embora não possamos fornecer um valor de tipo arbitráriob, mas sempre podemos fornecermzero do tipom b e de acordo com a lei, deve efetivamente impedir que todos os outros efeitos sejam computados) e captura o valor recebido como resultado final decallCC'.

Então, minha pergunta é:

Esta implementação funciona como esperado para um idealcallCC? Podemos implementarshift ereset com semântica adequada também?

Além do exposto, quero saber:

Para garantir o comportamento adequado, temos que assumir alguma propriedade deMonadRef. Então, quais seriam as leisMonadRef ter para fazer com que a implementação acima se comporte como esperado?

ATUALIZAR

Acontece que a implementação ingênua acima não é boa o suficiente. Para fazê-lo satisfazer "Continuação atual"

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

Temos que ajustar a implementação para

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

Em outras palavras, o originalMonadZero não basta, temos que conseguir combinar ummzero valor com um cálculo normal sem cancelar o cálculo inteiro.

O exposto acima não responde à pergunta, é apenas ajustado porque a tentativa original foi falsificada para ser candidata. Mas para a versão atualizada, as perguntas originais ainda são perguntas. Especialmente,reset eshift ainda estão para serem implementadas.

questionAnswers(1)

yourAnswerToTheQuestion