有一个众所周知的问题we cannot use forall
types in the Cont
return type。
但是,可以使用以下定义:
class Monad m => MonadCont' m where
callCC' :: ((a -> forall b. m b) -> m a) -> m a
shift :: (forall r.(a -> m r) -> m r) -> m a
reset :: m a -> m a
然后找到一个有意义的实例。在this paper中,作者声称我们可以在MonadFix
之上实施ContT r m
,前提是m
已实施MonadFix
和MonadRef
。但我认为,如果我们确实有MonadRef
,我们实际上可以实现callCC'
,如下所示:
--satisfy law: mzero >>= f === mzero
class Monad m => MonadZero m where
mzero :: m a
instance (MonadZero m, MonadRef r m) => MonadCont' m where
callCC' k = do
ref <- newRef Nothing
v <- k (\a -> writeRef ref (Just a) >> mzero)
r <- readRef ref
return $ maybe v id r
shift = ...
reset = ...
(不幸的是,我不熟悉shift
和reset
的语义,所以我没有为它们提供实现)
这个实现对我来说似乎没问题。直观地,当callCC'
被调用时,我们向k
提供其自身效果始终失败的函数(尽管我们无法提供任意类型b
的值,但我们可以始终提供类型为mzero
的{{1}},并且根据法律,它应该有效地停止计算所有进一步的效果),并将接收到的值作为m b
的最终结果。
所以我的问题是:
此实施是否符合理想callCC'
的预期效果?我们是否可以使用适当的语义实现callCC
和shift
?
除了上述内容,我想知道:
为了确保正确的行为,我们必须假设reset
的某些属性。那么为了使上述实现具有预期的行为,MonadRef
所具有的法律是什么?
更新
事实证明,上述天真的实现还不够好。使其满足&#34;延续当前&#34;
MonadRef
我们必须将实施调整为
callCC $\k -> k m === callCC $ const m === m
换句话说,原始instance (MonadPlus m, MonadRef r m) => MonadCont' m where
callCC' k = do
ref <- newRef mzero
mplus (k $ \a -> writeRef ref (return a) >> mzero) (join (readRef ref))
是不够的,我们必须能够使用正常计算将MonadZero
值组合而不取消整个计算。
以上内容没有回答这个问题,只是因为最初的尝试被伪造为候选人而进行了调整。但对于更新版本,原始问题仍然是问题。特别是,mzero
和reset
仍有待实施。
答案 0 :(得分:2)
(这还不是一个答案,但只有一些线索出现在我的脑海里。我希望这会通过我自己或其他人得到真正的答案。)
Call-by-Value is Dual to Call-by-Name - Philip Wadler
在上面的论文中,作者介绍了&#34; Dual Calculus&#34;,这是一种与经典逻辑相对应的类型演算。在上一节中,有一段称为
双重呼吁的策略可以 通过用其covalue覆盖coterm来避免这种低效率 第一次评估。
正如Wadler的论文中所述,逐个名称地逐个评估连续性(它在所有被评估的值之前返回),同时按值调用延迟评估连续性(它仅在所有值被评估之后返回) )。
现在,看一下上面的callCC'
,我相信这是继续方面的双重需求的双重例子。评估的策略是提供假的继续&#34;到给定的函数,但在此时缓存状态以调用&#34; true&#34;继续以后。这就像制作延续的缓存一样,所以一旦计算完成,我们就恢复那个延续。但缓存评估值是指按需调用的含义。
一般来说,我怀疑,状态(计算到当前时间点)是连续的两倍(未来的计算)。这将解释一些现象。如果这是真的,那么MonadRef
(对应于全局和多态状态)对MoncadCont
是双重的(对应于全局和多态连续)并不奇怪,因此它们可用于实现彼此。