haskell - 如何提取定界延续(重置/移位)以供将来在 Haskell 中使用?

标签 haskell continuations delimited-continuations

以下是使用定界延续(重置/移位)的简单示例:

import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.Cont

test :: Integer
test = evalCont . reset $ do
    r <- shift $ \k -> do
        return $ k 10
    return $ 1 + r

λ> test1
11

效果不错。

但是,我想将延续 k 提取为纯函数以供将来使用,而不是仅仅在 shift 中调用它。

比如我希望test2可以返回k:

test2 :: Integer -> Integer
test2 = evalCont . reset $ do
    r <- shift $ \k -> do
        return $ k
    return $ 1 + r

但是 GHC 提示:

    ? Couldn't match type 'Integer -> Integer' with 'Integer'
      Expected type: Cont (Integer -> Integer) (Integer -> Integer)
        Actual type: ContT
                       (Integer -> Integer)
                       Data.Functor.Identity.Identity
                       ((Integer -> Integer) -> Integer -> Integer)
    ? In a stmt of a 'do' block: return $ k
      In the expression: do return $ k
      In the second argument of '($)', namely '\ k -> do return $ k'
   |
88 |         return $ k
   |         ^^^^^^^^^^

谁能帮我解决这个问题?

谢谢。

最佳答案

标准的 Cont 是不完全通用的。 “真实”Cont 看起来像这样

newtype Cont    i o a =    Cont { runCont :: (a -> i) -> o }
-- versus the standard
newtype SadCont   r a = SadCont { sadCont :: (a -> r) -> r }
-- SadCont r a = Cont r r a

使用标准的 SadCont 是因为它支持 >>=return 它们通常的类型(所以它可以是一个 单子(monad)).但是 Cont 中的“真正的”分隔延续允许每个 shift 从延续中获取一种类型的值并将它们发送到前一个 shift/重置 为不同的类型。在这种情况下,您只是将 整个 延续作为从 shiftreset 的函数传递。

{-# LANGUAGE RebindableSyntax #-}
-- ^ placing this at the top of a file or passing -XRebindableSyntax to GHC allows do notation to use custom (>>=) and (>>)

-- not Monad operations!
return :: a -> Cont r r a
return x = Cont ($ x)
(>>=) :: Cont m o a -> (a -> Cont i m b) -> Cont i o b
Cont x >>= f = Cont $ \k -> x (($ k) . runCont . f)
(>>) :: Cont m o a -> Cont i m b -> Cont i o b -- RebindableSyntax also wants this
a >> b = a >>= const b

evalCont :: Cont a o a -> o
evalCont (Cont x) = x id

-- shift/reset are actually just
reset = evalCont
shift = Cont
-- note that the types of reset and shift differ significantly from transformers
-- reset returns a pure value here and shift requires a pure value from its function
-- I think my choices are more correct/standard, e.g. they line up with the old Scala shift/reset http://lampwww.epfl.ch/~hmiller/scaladoc/library/scala/util/continuations/package.html

在你的例子中

test2 :: Integer -> Integer
test2 = reset $ do
    r <- shift $ \k -> k
    return $ 1 + r

TL;DR Cont 被故意“破坏”,因此它失去了不同输入和输出类型的通用性,但获得了 Monadicity。您可以通过将输入和输出类型放入您发现的(递归)总和来破解它。或者(这个答案)你可以定义和使用“真实的”Cont

关于haskell - 如何提取定界延续(重置/移位)以供将来在 Haskell 中使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72833519/

相关文章:

haskell - 不断出现堆栈溢出

Haskell 递归和类型错误

smalltalk - Smalltalk 如何操作调用栈帧(thisContext)?

asynchronous - 异步/等待模式和延续之间的关系是什么?

Scala 在运行时分隔连续错误

haskell - 连续单子(monad)转变

haskell - HXT:在 Haskell 中使用 HXT 按位置选择节点?

haskell - 为什么 Haskell 要求对 printf 的数字进行消歧,而不是对 show 进行消歧?

javascript - 如何在 JavaScript 等动态语言中实现延续?

continuations - 为什么 PyPy 1.7 不实现 "stackless"堆栈?