ContT Monad:将各个部分放在一起

The ContT Monad: Putting the pieces together

序言

我正在努力思考如何实际使用 ContTcallCC 来做一些有用的事情。我在跟踪代码周围的信息和控制流时遇到了问题。 (但是,这不是继续的意义吗?)

有很多不同的方法可以使用这个 monad 和一小部分不是很直接的组合器来移动片段。我承认我对我对 ContT 工作原理的理解仍然不自在,但我会指出我目前所读的内容:

我想做的是post一个伪代码示例,然后问一些关于它的问题。这表示使用 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

问题

  1. 什么决定了 output 的值和类型?
  2. bk类型中是什么意思?
  3. 赋予k的价值去了哪里?
  4. 什么时候inner_block运行?它看到什么版本的状态?
  5. rval 去了哪里,它的类型是什么?
  6. krval有什么关系?
  7. 当我应用 k a) 在 inner_block、b) 在 after_callcc、c) 在 block 之外时会发生什么?
  8. 以上每个状态的版本是什么?
  9. 我需要做什么才能从 block 中获得 k
  10. 我可以把k放入状态吗?

颜色编码以便于阅读

  1. What determines the value and type of output?

它将与 rval 的类型相同。该值也将相同,除非 inner_block 使用 k someValue 转义块的其余部分。在这种情况下,output 将是 someValue

  1. What does the b mean in the type of k?

粗略地说,b可以理解为"anything at all"。也就是说,如果inner_block

...
v <- k someValue
use v

然后 v :: b。但是,k someValue 永远不会 运行 块的其余部分,因为它会立即退出 callCC。因此,不会返回 v 的具体值。因此 v 可以有任何类型:use 是否需要 StringInt 并不重要——它不会被执行。

  1. Where does the value given to k go?

一旦内部块 运行s k someValue 值由 callCC 返回为 output,块的其余部分将被跳过。

  1. When is inner_block run? What version of the state does it see?

它是 运行,因为 callCC 被调用,并且看到的状态与我们当时的状态相同。

  1. Where does rval go and what its type?

进入output。同款。

  1. What is the relationship between k and rval?

rvalk.

的参数类型相同
  1. What happens when I apply k a) in inner_block, b) in after_callcc, c) outside of block?

a) 见上文。 b) k 超出了 after_callcc 的范围。 c) 也不在范围内。

  1. What is the version of the state in each of the above?

该州是 "current" 州。 (我不确定你到底想问什么)

  1. What do I need to do to get k out of block?

我想这里需要递归类型。这是一个尝试:

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")
  1. Can I put k into the state?

我相信你也需要一个递归类型。