前言
我试图围绕如何实际使用ContT
和callCC
获得有用的信息。我在遵循代码的信息和控制流程时遇到了麻烦。 (但是,这不是延续的重点吗?)
使用此monad可以有很多不同的移动方式,也有少数不是很简单的组合器。我承认我对ContT的工作原理仍然不满意,但是我要指出到目前为止我已经读到的内容:
我想做的是发布一个伪代码示例,然后问一些有关它的问题。这代表使用ContT的典型代码外观
伪代码
type MyMonad r = ContT r (State SomeState)
main = do
runState s_init $ runContT block print
block :: MyMonad r a0
block = do
before_callcc
output <- callCC $ \k -> do
rval <- inner_block
return rval
after_callcc
问题
output
的值和类型? b
在k
类型中是什么意思? k
的值在哪里? inner_block
?它看到哪个状态的状态? rval
会去哪里,它的类型是什么? k
和rval
之间是什么关系? k
中应用inner_block
,在after_callcc
中应用b),在block
中应用b,在k
之外应用c)时会发生什么? block
中获取k
? 颜色编码使阅读更容易
最佳答案
它将与rval
具有相同的类型。该值也将是相同的,除非inner_block
使用k someValue
逃脱了块的其余部分。在这种情况下,output
将为someValue
。
大致来说,b
可以理解为“任何东西”。也就是说,如果inner_block
是
...
v <- k someValue
use v
然后
v :: b
。但是,k someValue
将永远不会运行该块的其余部分,因为它将立即退出callCC
。因此,将不会返回v
的具体值。因此,v
可以具有任何类型:use
是否需要String
或Int
都没关系-无论如何它都不会执行。内部块一旦运行
k someValue
,callCC
就会将其值返回为output
,其余的块将被跳过。它在调用
callCC
时运行,并且看到的状态与我们那时的状态相同。放入
output
中。相同的类型。rval
与k
的参数具有相同的类型。a)见上文。
b)
k
超出了after_callcc
的范围。c)也超出范围。
状态是“当前”状态。 (我不确定您在这里到底要什么)
我猜想这里需要一个递归类型。这是一个尝试:
import Control.Monad.Cont
import Control.Monad.State
import Control.Monad.Trans
type SomeState = String
type MyMonad r = ContT r (State SomeState)
newtype K a b r = K ((K a b r, a) -> MyMonad r b)
main = do
print $ flip runState "init" $ runContT block return
block :: MyMonad r Int
block = do
lift $ modify (++ ":start")
(K myK, output) <- callCC $ \k -> do
s <- lift $ get
lift $ modify (++ ":inner(" ++ show (length s) ++")")
return (K k, 10)
lift $ modify (++ ":output=" ++ show output)
s <- lift $ get
when (length s <50) $ myK (K myK, output+1)
return 5
此打印
(5,"init:start:inner(10):output=10:output=11:output=12")
我相信您也需要为此使用递归类型。