Используйте 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. Но я думаю, есть ли у нас действительно a 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 таким образом, я не предоставлял реализации им),

Эта реализация кажется OK для меня. Интуитивно, когда callCC' будучи позвонившимся, мы питаемся k который функция, что ее собственный эффект всегда является сбоем (хотя мы не можем обеспечить значение произвольного типа b, но мы можем всегда обеспечивать mzero из типа m b и согласно закону это должно эффективно остановить все дальнейшие вычисляемые эффекты), и это получает полученное значение как конечный результат callCC'.

Таким образом, мой вопрос:

Эта реализация работы как ожидалось для идеала callCC? Мы можем реализовать shift и reset с надлежащим, семантическим также?

В дополнение к вышеупомянутому я хочу знать:

Для обеспечения надлежащего поведения, мы должны принять некоторое свойство MonadRef. Таким образом, что было бы законы a 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 недостаточно, мы должны смочь к объединенному a mzero значение с нормальным вычислением, не отменяя целое вычисление.

Вышеупомянутое не отвечает на вопрос, оно просто корректируется, поскольку исходная попытка была сфальсифицирована, чтобы быть кандидатом. Но для обновленной версии, исходными вопросами являются все еще вопросы. Особенно, reset и shift должны все еще быть реализованы.

63
задан 23 May 2017 в 15:02

1 ответ

(Это еще не ответ, но только некоторые подсказки подошли в моем уме. Я надеюсь, что это приведет к реальному ответу, один или кем-то еще.)

Вызов по значению является Двойным к Вызову по имени - Philip Wadler

В вышеупомянутой газете, автор представил "Двойное Исчисление", введенное исчисление, которое соответствует классической логике. В последнем разделе существует сегмент, говорит

, стратегия А, двойная к вызову по необходимости, могла избежать этой неэффективности путем перезаписи coterm с его covalue в первый раз, когда это оценено.

, Как указано в статье Wadler, вызов по имени, оценивая продолжения нетерпеливо (это возвращается перед всеми оцениваемыми значениями), пока вызов по значению, оценивая продолжения лениво (это только возвращается после всех оцениваемых значений).

Теперь, смотрите на callCC' выше, я полагаю, что это - пример двойного из вызова по необходимости в стороне продолжения. Стратегия оценки, это предоставляет поддельное "продолжение" данной функции, но кэширует состояние в этой точке для вызова "истинного" продолжения позже. Это так или иначе похоже на создание кэша продолжения, и поэтому после того как вычисление заканчивается, мы восстанавливаем то продолжение. Но кэшируйтесь, оцененное значение - то, что оно подразумевает под вызовом по необходимости.

В целом я подозреваю, состояние (вычисление до текущего момента времени) является двойным к продолжению (будущее вычисление). Это объяснит несколько явлений. Если это верно, это не удивление, которое MonadRef (соответствуют глобальному и полиморфному состоянию) является двойным к MoncadCont (соответствуйте глобальным и полиморфным продолжениям), и таким образом, они могут использоваться для реализации друг друга.

2
ответ дан 31 October 2019 в 13:01

Другие вопросы по тегам:

Похожие вопросы: