如何使callCC更具动态性?

时间:2011-08-24 16:23:53

标签: haskell continuations 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类型检查,也不知道该怎么做。 我设法进行shiftreset类型检查

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

但是,我仍然不能在这样的递归跳转中使用shiftreset吗?

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

以前有人试过吗?

2 个答案:

答案 0 :(得分:27)

答案 1 :(得分:1)

虽然没有办法赢得给定的比赛,如果我们可以稍稍扭转一下比赛,我们就可以获胜!

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

正如我们在另一个答案中看到的那样,我们遇到的问题是,为了获胜,我们必须为对手所玩的任意类型生成一个值,但我们不知道该怎么做。

通过强制r装饰所有原始类型(aMaybe),我们可以绕过此问题,并且能够生成任何Maybe t的值 - 简单地给他们Nothing

我们要证明这是一个Monad

instance Monad m => Monad (ContT' m) where
    return a = ContT' $ \k -> k (Just a)
    a >>= f = ContT' $ \c -> runContT' a (
        maybe (return Nothing) (\v -> runContT' (f v) c)) 

然后我们可以实施callCC

class Monad m => MonadCont' m where
    callCC' :: ((a -> forall b.m b) -> m a) -> m a

instance Monad m => MonadCont' (ContT' m) where
    callCC' k = ContT' $ \c -> 
        runContT' (k (\a -> ContT' $ \_ -> c (Just a) >> return Nothing)) c  

我仍在研究如何实施resetshift