11

前言

我正试图围绕如何实际使用ContTcallCC寻找有用的东西。我在跟踪代码周围的信息和控制流时遇到了麻烦。(但是,这不是延续的意义吗?)

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

我想做的是发布一个伪代码示例,然后问一些关于它的问题。这代表了使用 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. b的类型是什么意思k
  3. 赋予的价值k去哪儿了?
  4. 什么时候inner_block运行?它看到的是什么版本的状态?
  5. 去哪里rval,它的类型是什么?
  6. k和之间有什么关系rval
  7. 当我申请ka) in inner_block, b) in after_callcc, c) outside 时会发生block什么?
  8. 上述每个状态的版本是什么?
  9. 我需要做什么才能k摆脱block
  10. 我可以放入k状态吗?

颜色编码,便于阅读

颜色编码示例

4

1 回答 1

4
  1. 是什么决定了它的价值和类型output

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

  1. b的类型是什么意思k

粗略地说,b可以理解为“什么都没有”。也就是说,如果inner_block

...
v <- k someValue
use v

然后v :: b。但是,k someValue永远不会运行块的其余部分,因为它会callCC立即退出。因此,不会返回任何具体的值v。因为它v可以有任何类型:不管是userequires aString还是 an都没有关系Int——反正它不会被执行。

  1. 赋予的价值k去哪儿了?

一旦内部块运行k someValue,值就会由callCCas返回output,并跳过块的其余部分。

  1. 什么时候inner_block运行?它看到的是什么版本的状态?

它按callCC调用方式运行,并看到与我们当时相同的状态。

  1. 去哪里rval,它的类型是什么?

output。同类型。

  1. k和之间有什么关系rval

rval具有与 的参数相同的类型k

  1. 当我申请ka) in inner_block, b) in after_callcc, c) outside 时会发生block什么?

a) 见上文。b)k超出after_callcc. c) 也超出范围。

  1. 上述每个状态的版本是什么?

状态是“当前”状态。(我不确定你到底在这里要求什么)

  1. 我需要做什么才能k摆脱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. 我可以放入k状态吗?

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

于 2015-09-06T06:38:08.523 回答