Как сделать callCC более динамичным?

Я думал, что правильным типом для ContT должен быть

newtype ContT m a = ContT {runContT :: forall r. (a -> m r) -> m r}

и другие операторы управления

shift :: Monad m => (forall r. (a -> ContT m r) -> ContT m r) -> ContT m a
reset :: Monad m => ContT m a -> ContT m a
callCC :: ((a -> (forall r. ContT m r)) -> ContT m a) -> ContT m a

К сожалению, я не могу выполнить проверку типа callCC и не знаю, как это сделать. сделай это. Мне удалось сделать shift и reset type check

reset :: Monad m => ContT m a -> ContT m a
reset e = ContT $ \ k -> runContT e return >>= k

shift :: Monad m => (forall r. (a -> ContT m r) -> ContT m r) -> ContT m a
shift e = ContT $ \ (k :: a -> m r) ->
    runContT ((e $ \ v -> ContT $ \c -> k v >>= c) :: ContT m r) return

, но я все равно не могу использовать shift и reset в рекурсивных переходах как это?

newtype H r m = H (H r m -> ContT m r)

unH (H x) = x

test = flip runContT return $ reset $ do
    jump <- shift (\f -> f (H f))
    lift . print $ "hello"
    unH jump jump

Кто-нибудь пробовал это раньше?

22
задан Benjamin Hodgson 21 February 2017 в 19:52
поделиться