由于以下是阻止:
do
x <- foo
y <- bar
return x + y
是以下形式:
foo >>= (\x -> bar >>= (\y -> return x + y))
这里不是\x -> ...
和y -> ...
实际延续吗?
我想知道是否有一种方法可以捕获bind
定义中的延续,但我无法确定正确的类型。即:
data Pause a = Pause a | Stop
instance Monad Pause where
return x = Stop
m >>= k = Pause k -- this doesn't work of course
现在我尝试使用以下类型进行混淆:
data Pause a = Pause a (a -> Pause ???) | Stop
------- k ------
但这也不起作用。有没有办法捕捉这些隐含的延续?
是的,我知道Cont
monad,我只是在试验和尝试。
答案 0 :(得分:1)
好的,我不太确定,但让我提出一些想法。我不太确定它是什么
应该意味着抓住延续。例如,你可以捕获整体
do
在结构中阻止:
{-# LANGUAGE ExistentialQuantification #-}
import Control.Monad
data MonadExp b = Return b | forall a. Bind (MonadExp a) (a -> MonadExp b)
instance Monad MonadExp where
return x = Return x
f >>= g = Bind f g
例如:
block :: MonadExp Int
block = do
x <- return 1
y <- return 2
return $ x + y
instance Show (MonadExp a) where
show (Return _) = "Return _"
show (Bind _ _) = "Bind _ _"
print block
>> Bind _ _
然后评估整个事情:
finish :: MonadExp a -> a
finish (Return x) = x
finish (Bind f g) = finish $ g (finish f)
print $ finish block
>> 3
或者单步执行并查看部分
step :: MonadExp a -> MonadExp a
step (Return _) = error "At the end"
step (Bind f g) = g $ finish f
print $ step block
>> Bind _ _
print $ step $ step block
>> Return _
嗯,现在我想的更多,那可能不是你要问的。但 也许它会帮助你思考。
答案 1 :(得分:1)
好吧,我不知道你的lambdas是否是最严格意义上的延续,但它们在我看来也与这个概念类似。
但是请注意,如果它们是延续的话,那么脱落的monadic代码已经用连续传递方式(CPS)编写了。 “捕获”延续的控制操作员的通常概念是基于直接式程序; “捕获”延续仅隐含在直接式程序中,但CPS转换使其明确。
由于desadared monadic代码已经在CPS或类似的东西,好吧,也许一种解决问题的方法是monadic代码是否可以表达CPS代码可以表达的一些控制流技巧。通常情况下,这些技巧归结为这样的想法,即在CPS制度下,通过调用其延续来完成一个函数是常规的,一个函数可以选择替换它的继续与另一个选择。这个替换延续可以通过引用原始延续来构造,以便它可以反过来“恢复”原始延续,如果它选择的话。因此,例如,协同程序被实现为相互“替换/恢复”循环。
从这个角度来看,我认为你的答案基本上没有; CPS要求在foo >>= bar
中,foo
必须能够选择是否会调用bar
,foo
必须能够替代bar
但是,(>>=)
本身并不提供foo
执行此操作的机制,更重要的是,(>>=)
控制着执行流程,而不是foo
。一些特定的monad实现部分或全部(例如,Maybe
monad允许foo
通过生成bar
结果而放弃Nothing
的执行,但其他人不要吨。
我能得到的最近的就是放弃(>>=)
并改为使用它:
-- | Execute action @foo@ with its "continuation" @bar@.
callCC :: Monad m => ((a -> m b) -> m b) -> (a -> m b) -> m b
foo `callCC` bar = foo bar
此处foo
可以选择是否会使用bar
。但请注意,此callCC
实际上只是($)
!