【问题标题】:How to express delimited continuations with pure functions only?如何仅用纯函数表示定界延续?
【发布时间】:2019-06-01 08:15:05
【问题描述】:

我完成了 Oleg 的 tutorial 的定界延续:

newtype Cont r a = Cont{runCont :: (a -> r) -> r}

instance Monad (Cont r) where
  return x = Cont (\k -> k x)
  Cont m >>= f = Cont (\k -> m (\v -> runCont (f v) k))

runC :: Cont r r -> r
runC m = runCont m id

reset :: Cont a a -> Cont r a
reset = return . runC

shift :: ((a -> r) -> Cont r r) -> Cont r a
shift f = Cont (runC . f)

liftM2 (-)
  (reset
    (liftM2 (+) (return 3)
      (shift (\k -> return (5*2))))) -- drop the continuation
        (return 1) -- 9

由于延续基本上是函数,reset/shift 甚至不是 monad api 的一部分,我想知道如何在没有 newtype 和 monad 机制的情况下实现分隔延续。

这是我目前的想法:

reset :: Cont a a -> Cont r a -- becomes
reset :: ((a -> a) -> a) -> (a -> r) -> r
reset k f = f $ k id

shift :: ((a -> r) -> Cont r r) -> Cont r a -- becomes
shift :: ((a -> r) -> (r -> r) -> r) -> (a -> r) -> r
shift f k = f k id

我很确定这是完全错误的,如果不是,我不知道如何正确应用运算符:

(1-) (reset ((3+) (shift (\k -> 5*2)))) -- yields

• Non type-variable argument in the constraint: Num ((a -> a) -> a)
  (Use FlexibleContexts to permit this)
• When checking the inferred type
    t1 :: forall a r.
          (Num ((a -> a) -> a), Num ((a -> r) -> r)) =>
          (a -> r) -> r

【问题讨论】:

  • 我不知道 (U+2217) 是什么字符,但肯定不是星号* (U+002A)。该错误可能会告诉您类似的信息,这就是为什么您应该将其放在您的问题中,而不仅仅是说“编译错误”。

标签: haskell continuations continuation-passing delimited-continuations


【解决方案1】:

继续!

import Prelude hiding (return)

-- reset :: Cont a a -> Cont r a
reset :: ((a -> a) -> a) -> (a -> r) -> r
reset k f = f $ k id

-- shift :: ((a -> r) -> Cont r r) -> Cont r a
shift :: ((a -> r) -> (r -> r) -> r) -> (a -> r) -> r
shift f k = f k id

-- return :: a -> Cont r a
return :: a -> (a -> r) -> r
return a k = k a

-- liftM2 :: (a -> b -> c) -> Cont r a -> Cont r b -> Cont r c
liftM2 :: (a -> b -> c) -> ((a -> r) -> r) -> ((b -> r) -> r) -> (c -> r) -> r
liftM2 f ma mb k = ma $ \a -> mb $ \b -> k (f a b)

example :: Num a => (a -> r) -> r
example = liftM2 (-) (reset (liftM2 (+) (return 3) (shift (\k -> return (5*2))))) (return 1)

(1-) (reset ((3+) (shift (\k -> 5*2)))) 的一个问题是您将Contreturn 替换为id,而实际上它是flip id

λ :t shift (\k -> 5*2)
shift (\k -> 5*2) :: Num ((r -> r) -> r) => (a -> r) -> r
λ :t shift (\k -> ($ 5*2))
shift (\k -> ($ 5*2)) :: Num r => (a -> r) -> r

通常,当 ghci 说“我们需要能够将函数视为数字才能使这段代码正常工作”时,这意味着你在某个地方犯了一个错误 :)

【讨论】:

  • 当然,我仍然需要return 和二进制提升操作,即使两者不再属于 monad 类。非常感谢!
猜你喜欢
  • 2011-08-28
  • 2019-07-10
  • 2014-01-22
  • 2012-02-09
  • 2011-04-07
  • 1970-01-01
  • 2016-12-11
  • 2019-04-15
  • 2021-10-17
相关资源
最近更新 更多