这个问题与"阴阳谜如何运作?"有关..根据维基百科的文章,阴阳计划中的延续例子如下所示:
(let* ((yin
((lambda (cc) (display #\@) cc) (call-with-current-continuation (lambda (c) c))))
(yang
((lambda (cc) (display #\*) cc) (call-with-current-continuation (lambda (c) c)))))
(yin yang))
Run Code Online (Sandbox Code Playgroud)
我试图用(编辑:静态)类型的语言编写一个等效的代码片段,例如SML/NJ,但是它给了我输入错误.所以要么拼图不输入,要么我误解了方案语法.上面的代码在SML或Ocaml(带callcc扩展名)中会是什么样的?
顺便问一下,这个谜题的来源是什么?它从哪里来的?
编辑:我想我知道答案.我们需要一种t满足t = t -> s某种类型的递归类型s.
编辑编辑:不,不是,答案是一个t令人满意的递归类型t = t -> t.
对于我的生活,我无法理解延续.我认为这个问题源于我不明白它们的用途.我在书籍或网上找到的所有例子都非常简单.他们让我想知道,为什么有人甚至想要延续?
这是一个典型的不切实际的例子,来自TSPL,我认为这是一本非常公认的关于这个主题的书.在英语中,他们将继续描述为计算结果的"做什么".好的,这是可以理解的.
然后,第二个例子给出:
(call/cc
(lambda (k)
(* 5 (k 4)))) => 4
Run Code Online (Sandbox Code Playgroud)
这有什么用?k甚至没有定义!当(k 4)无法计算时,如何评估此代码?更何况,如何call/cc知道撕掉4最内层表达式的参数并返回它?会发生什么事(* 5 ..?如果这个最外层的表达式被丢弃,为什么要写呢?
然后,陈述的"较少"的简单示例是如何使用call/cc来提供递归的非本地退出.这听起来像流控制指令,即break/return在命令式语言中,而不是计算.
通过这些动议的目的是什么?如果有人需要计算结果,为什么不只是存储它并在以后根据需要调用.
在Haskell中创建monad 时,是否有任何关于何时使用延续传递样式与密度和反射而没有悔恨的经验法则?
举个例子,我将使用一个简单的协程monad.如果您以前从未见过这个,可能需要查看Monad.Reader Issue 19中的"Coroutine Pipelines"文章或管道库.可以在此存储库中找到以下示例的完整代码.
正常
这只是一个定义为数据类型的普通monad:
data FooM i o a
= Await (i -> FooM i o a)
| Yield o (FooM i o a)
| Done a
Run Code Online (Sandbox Code Playgroud)
这种风格被广泛用于Haskell生态系统.这种风格的一个例子是Proxy来自的数据类型pipes.
延续传球风格(CPS)
这类似于普通样式,但每个数据构造函数都成为延续的参数:
newtype FooCPS i o a = FooCPS
{ runFooCPS
:: forall r.
((i -> FooCPS i o a) -> r)
-> (o -> FooCPS i o a -> …Run Code Online (Sandbox Code Playgroud)问题说明了一切.
(然而,多年来,如何访问shift和reset操作的细节已经发生了变化.旧的博客条目和Stack Overflow答案可能有过时的信息.)
另请参阅什么是Scala延续以及使用它们的原因?其中谈到你可能想用做什么shift和reset一旦你有他们.
我正在尝试破译文档
call-with-continuation-prompt适用
proc于给定的args,当前延续由提示扩展.提示标记为prompt-tag,必须是default-continuation-prompt-tag(默认)或的结果make-continuation-prompt-tag.结果proc是call-with-continuation-prompt调用的结果.
我理解它所说的"适用proc于arg当前延续的给定s"的部分,然后它就是那里的乱码.
对于延续"延伸"甚至意味着什么,以及"提示"如何"延伸"?
我竭力要了解准确意思,当值的类型A @cpsParam[B,C]和使用分隔延续设施时,我应该分配给我的价值观是什么类型的这种形式.
我看过一些消息来源:
http://lamp.epfl.ch/~rompf/continuations-icfp09.pdf
http://www.scala-lang.org/node/2096
http://dcsobral.blogspot.com/2009/07/delimited-continuations-explained-in.html
http://blog.richdougherty.com/2009/02/delimited-continuations-in-scala_24.html
但他们没有给我很多直觉.在最后一个链接中,作者试图给出明确的解释,但无论如何还不够明确.
这里的A代表计算的输出,它也是其继续的输入.在B表示延续的返回类型,而C表示其"最终"返回类型-因为移可以做进一步的处理,以返回值,并改变其类型.
我不明白"计算的输出","延续的返回类型"和"延续的最终返回类型"之间的区别.他们听起来像同义词.
关于Continuation的维基百科文章说:
"在任何支持闭包的语言中,都可以用连续传递方式编写程序并手动实现call/cc."
这是真的,我需要知道如何做或不是真的,这个陈述需要纠正.
如果这是真的,请告诉我如何在Lua中实现call/cc,因为我看不清楚如何.
我想我能够实现来电/立方厘米,如果手动Lua中有coroutine.clone功能解释在这里.
如果闭包不足以实现call/cc那么还需要什么呢?
以下文字是可选阅读.
PS:Lua与其协程表一次性延续.一个coroutine.clone函数允许我克隆它多次调用它,从而有效地使call/cc成为可能(除非我误解了call/cc).但是Lua中不存在克隆功能.Lua IRC频道上的某个人建议我使用Pluto库(它实现序列化)来编组协程,复制它然后解组它并再次使用它.虽然这可能会奏效,但我更感兴趣的是call/cc的理论实现,以及查找语言需要具有的实际最小特征集以便允许其手动实现.
编辑1:好的人,帮我在这里,这花了我很长时间,因为我不知道任何计划,但我想出了一些应该帮助我们的东西.请看下面的代码.第一个是Scheme中的程序,第二个是相同的程序,但在Lua中.
希望这会帮助我们.我相信我们非常接近.
PS:这些例子来自关于CallCC的维基百科文章的第一个例子.
方案版
(define call/cc call-with-current-continuation)
; callcc CPS-transformed (thanks to the people from the #scheme channel at freenode.net)
(define cpscallcc
(lambda (consumer k)
(let ((cc (lambda (result) (k result))))
(consumer cc k))))
; this is the continuation we will use to display the "returned" values
(define main-continuation
(lambda (result)
(display "--> ")
(display result)
(newline)))
; …Run Code Online (Sandbox Code Playgroud) 我认为ContT的正确类型应该是
newtype ContT m a = ContT {runContT :: forall r. (a -> m r) -> m r}
Run Code Online (Sandbox Code Playgroud)
和其他控制操作员
shift :: Monad m => (forall r. (a -> ContT m r) -> ContT m r) -> ContT m a
reset :: Monad m => ContT m a -> ContT m a
callCC :: ((a -> (forall r. ContT m r)) -> ContT m a) -> ContT m a
Run Code Online (Sandbox Code Playgroud)
不幸的是,我无法进行callCC类型检查,也不知道该怎么做.我设法制作shift并reset打字检查
reset :: Monad m => …Run Code Online (Sandbox Code Playgroud) continuations ×10
scheme ×4
haskell ×3
callcc ×2
free-monad ×2
monads ×2
scala ×2
types ×2
lisp ×1
lua ×1
racket ×1
reflection ×1
scala-2.8 ×1