我刚刚完成了Programming in Scala,并且我明白它已经看到了它已经找到了原因 . 它已经找到了原因 . 关于这个主题的一些更受欢迎的资源是:
关于Stack Overflow的这个问题:
不幸的是,这些引用中没有一个试图定义什么是continuation或者shift / reset函数应该做什么,而且我没有找到任何引用 . 我无法猜测链接文章中的任何示例是如何工作的(或者他们做了什么),因此帮助我的一种方法可能是逐行浏览其中一个示例 . 即使是第三篇文章中的简单文章:
reset {
...
shift { k: (Int=>Int) => // The continuation k will be the '_ + 1' below.
k(7)
} + 1
}
// Result: 8
为什么结果是8?这可能会帮助我开始 .
6 回答
我的blog确实解释了
reset
和shift
的作用,所以你可能想再读一遍 .另一个很好的来源,我也在我的博客中指出,是continuation passing style上的维基百科条目 . 到目前为止,这个问题是最明确的,尽管它没有使用Scala语法,并且显式传递了延续 .
关于分隔延续的论文,我在我的博客中链接但似乎已经破碎,提供了许多使用示例 .
但我认为分隔延续概念的最好例子是Scala Swarm . 在其中,库在一个点停止执行代码,剩余的计算成为延续 . 然后,库会执行某些操作 - 在这种情况下,将计算转移到另一个主机,并将结果(已访问的变量的值)返回到已停止的计算 .
现在,您甚至不了解Scala页面上的简单示例,所以请阅读我的博客 . 在其中我只关心解释这些基础知识,为什么结果是
8
.我发现现有的解释在解释这个概念方面不如我希望的那么有效 . 我希望这个清楚(并且正确 . )我还没有使用延续 .
当调用延续函数_2640429时:
执行跳过
shift
块的其余部分,并在其结尾处再次开始传递给
cf
的参数是shift
阻止"evaluates"继续执行的内容 . 对于每次拨打cf
,这可能会有所不同执行一直持续到
reset
块结束(或者直到调用reset
,如果没有阻塞)reset
块的结果(如果没有块,则为reset
()的参数)cf
返回在
cf
之后继续执行,直到shift
块结束执行跳过
reset
块结束(或重置调用?)因此,在此示例中,请遵循A到Z中的字母
这打印:
鉴于来自research paper的规范示例,对于Scala的分隔连续,稍微修改,因此函数输入
shift
的名称为f
,因此不再是匿名的 .Scala插件转换此示例,使得从
shift
开始到reset
调用的计算(在reset
的输入参数内)被输入到shift
的函数(例如f
)替换 .被替换的计算被移位(即移动)到函数
k
中 . 函数f
输入函数k
,其中k
包含替换的计算,k
输入x: Int
,k
中的计算用x
替换shift(f)
.其效果如下:
注意输入参数
x
的类型Int
(即k
的类型签名)由f
的输入参数的类型签名给出 .另一个具有概念等效抽象的示例,即
read
是shift
的函数输入:我相信这将被翻译成逻辑等同于:
我希望这可以阐明连贯的共同抽象,这些抽象通过先前介绍这两个例子而有些混淆 . 例如,规范的第一个例子在research paper中作为匿名函数呈现,而不是我的名字
f
,因此一些读者并不清楚它是抽象地类似于read
在borrowed第二个例子中 .因此,分隔的延续创造了一种控制反转的错觉,“你叫我从
reset
" to "我叫你在reset
” .注意
f
的返回类型是,但k
不是,需要与reset
的返回类型相同,即f
可以自由地为k
声明任何返回类型,只要f
返回与reset
相同的类型 . 同上read
和capture
(另见下面的ENV
) .定界延续不会隐含地反转状态控制,例如
read
和callback
不是纯函数 . 因此调用者不能创建引用透明的表达式,因此没有declarative (a.k.a. transparent) control over intended imperative semantics .我们可以使用分隔的continuation显式地实现纯函数 .
我相信这将被翻译成逻辑等同于:
由于环境明显,这会变得很吵 .
切向注意,Scala没有Haskell支持隐式提升到状态monad的
unit
(作为隐藏显式环境的一种可能策略),因为Haskell的全局(Hindley-Milner)类型推断依赖于not supporting diamond multiple virtual inheritance .继续捕获计算的状态,稍后调用 .
考虑离开shift表达式并将重置表达式保留为函数之间的计算 . 在shift表达式中,这个函数叫做k,它是continuation . 您可以传递它,稍后调用它,甚至不止一次 .
我认为重置表达式返回的值是=>之后的shift表达式内的表达式的值,但是对此我不太确定 .
因此,通过continuation,您可以在函数中包含一个相当任意且非本地的代码片段 . 这可用于实现非标准控制流程,例如协同处理或回溯 .
因此,应该在系统级别上使用continuation . 通过你的应用程序代码喷洒它们将是噩梦的必然配方,比使用goto的最糟糕的意大利面条代码更糟糕 .
免责声明:我对Scala中的延续没有深入的了解,我只是通过查看示例和了解Scheme的延续来推断它 .
从我的观点来看,这里给出了最好的解释:http://jim-mcbeath.blogspot.ru/2010/08/delimited-continuations.html
一个例子:
另一篇(最近的 - 2016年5月)关于Scala延续的文章是:
“Time Travel in Scala: CPS in Scala (scala’s continuation)”by Shivansh Srivastava (shiv4nsh) .
它还指Dmitry Bespalov的answer中提到的Jim McBeath的article .
但在此之前,它描述了Continuations,如下所示:
话虽如此,正如April 2014 for Scala 2.11.0-RC1所宣布的那样