我认为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
类型检查
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
以前有人试过吗?
答案 0 :(得分:27)
答案 1 :(得分:1)
虽然没有办法赢得给定的比赛,如果我们可以稍稍扭转一下比赛,我们就可以获胜!
newtype ContT' m a =
ContT' { runContT' :: forall r. (Maybe a -> m (Maybe r)) -> m (Maybe r) }
正如我们在另一个答案中看到的那样,我们遇到的问题是,为了获胜,我们必须为对手所玩的任意类型生成一个值,但我们不知道该怎么做。
通过强制r
装饰所有原始类型(a
和Maybe
),我们可以绕过此问题,并且能够生成任何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
我仍在研究如何实施reset
和shift
。