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.