Используйте MonadRef для реализации MonadCont
Существует хорошо известная проблема, котораямы не можем использоватьforall
вводит вCont
тип возврата.
Однако должно быть хорошо иметь следующее определение:
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
а затем найти экземпляр, который имеет смысл. ВЭта бумага автор утверждал, что мы можем реализоватьMonadFix
на вершинеContT r m
при условии чтоm
реализованыMonadFix
а такжеMonadRef
, Но я думаю, что если у нас естьMonadRef
мы можем реально реализоватьcallCC'
выше, как следующее:
--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 = ...
(К сожалению, я не знаком с семантикойshift
а такжеreset
поэтому я не предоставил реализации для них)
Эта реализация, кажется, хорошо для меня. Интуитивно, когдаcallCC'
будучи призванным, мы кормимk
что функция, что ее собственный эффект всегда терпит неудачу (хотя мы не можем предоставить значение произвольного типаb
, но мы всегда можем предоставитьmzero
типаm b
и в соответствии с законом он должен эффективно прекратить вычисление всех дальнейших эффектов), и он получает полученное значение как конечный результатcallCC'
.
Итак, мой вопрос:
Является ли эта реализация работает, как ожидается, для идеальногоcallCC
? Можем ли мы реализоватьshift
а такжеreset
с правильной семантикой?
В дополнение к вышесказанному, я хочу знать:
Чтобы обеспечить правильное поведение, мы должны принять некоторые свойстваMonadRef
, Так что бы законыMonadRef
иметь для того, чтобы заставить вышеупомянутую реализацию вести себя как ожидалось?
ОБНОВИТЬ
Оказывается, вышеописанная наивная реализация недостаточно хороша. Чтобы оно удовлетворяло "Ток продолжения"
callCC $\k -> k m === callCC $ const m === m
Мы должны приспособить реализацию к
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))
Другими словами, оригиналMonadZero
недостаточно, мы должны быть в состоянии объединитьmzero
значение с нормальным вычислением без отмены всего вычисления.
Вышесказанное не отвечает на вопрос, оно просто скорректировано, поскольку первоначальная попытка была сфальсифицирована, чтобы быть кандидатом. Но для обновленной версии оригинальные вопросы все еще остаются вопросами. Особенно,reset
а такжеshift
еще предстоит реализовать.