我刚刚完成了Scala编程,我一直在研究Scala 2.7和2.8之间的变化.似乎最重要的一个是continuation插件,但我不明白它对它有用或它是如何工作的.我已经看到它对异步I/O很有用,但我还是找不到原因.关于这个主题的一些更受欢迎的资源是:
关于Stack Overflow的这个问题:
不幸的是,这些引用中没有一个试图定义什么是continuation或者shift/reset函数应该做什么,而且我没有找到任何引用.我无法猜测链接文章中的任何示例是如何工作的(或者他们做了什么),因此帮助我的一种方法可能是逐行浏览其中一个示例.即使是第三篇文章中的简单文章:
reset {
...
shift { k: (Int=>Int) => // The continuation k will be the '_ + 1' below.
k(7)
} + 1
}
// Result: 8
Run Code Online (Sandbox Code Playgroud)
为什么结果是8?这可能会帮助我开始.
有一个众所周知的问题是我们不能forall在Cont返回类型中使用类型.
但是,可以使用以下定义:
class Monad m => MonadCont' m where
callCC' :: ((a -> forall b. m b) -> m a) -> m a
shift :: (forall r.(a -> m r) -> m r) -> m a
reset :: m a -> m a
Run Code Online (Sandbox Code Playgroud)
然后找一个有意义的实例.在本文中,作者声称我们可以MonadFix在ContT r m提供m实现MonadFix和实现之上实现MonadRef.但我想如果我们确实有一个,MonadRef我们可以实际上实现callCC'如下:
--satisfy law: mzero >>= f === mzero
class Monad m => MonadZero …Run Code Online (Sandbox Code Playgroud) 我想(一般来说)我的理解shift和reset意思.但是我不明白他们为什么如此命名?什么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"的部分,然后它就是那里的乱码.
对于延续"延伸"甚至意味着什么,以及"提示"如何"延伸"?
是否有人使用Haskell开发的分隔延续,特别是Web开发?我觉得这个话题很吸引人,我需要的东西比我学习的东西更容易获得.
以下是我到目前为止找到的资源:
谢谢!
-deech
在 1990 年代和 2000 年代,编程语言爱好者几乎没有讨论过分隔延续的话题。它最近重新成为编程语言讨论中的一个主要问题。
我希望有人至少可以权威地说出 Rakudo 背后的延续(与 Raku 相比)是否具有下面列出的六个特征中的每一个。在列表之后,我会多说一些我希望得到的答案。
从在线消息[1] 中逐字引用(带有格式修饰),该消息由推动向 JVM 添加延续的工作的人撰写:
非对称:当延续挂起或让步时,执行返回到调用者(of Continuation.run())。对称延续没有调用者的概念。当他们让步时,他们必须指定另一个延续以将执行转移到。对称延续和非对称延续都不比彼此更强大,每个都可以用来模拟另一个。
Stackful:延续可以在调用堆栈中的任何深度挂起,而不是在延续是无堆栈时(如 C# 中的情况)在分隔上下文开始的同一子例程中。即延续有自己的堆栈,而不仅仅是单个子程序帧。有堆栈的延续比无堆栈的更强大。
Delimited:continuation 捕获从特定调用开始的执行上下文(在我们的例子中,是某个 runnable 的主体),而不是一直到 的整个执行状态main()。带分隔符的延续严格来说比未分隔的延续更强大 ( http://okmij.org/ftp/continuations/undelimited.html ),后者被认为“没有实际用处”( http://okmij.org/ftp/continuations/against- callcc.html)。
Multi-prompt:Continuations 可以嵌套,并且在调用堆栈中的任何地方,任何封闭的 continuations 都可以被挂起。这类似于 try/catch 块的嵌套,并抛出某种类型的异常,将堆栈展开到最近的处理它的catch而不仅仅是最近的 catch。嵌套延续的一个例子是在虚拟线程中使用类似 Python 的生成器。生成器代码可以做一个阻塞 IO 调用,这将挂起封闭线程的延续,而不仅仅是生成器:https : //youtu.be/9vupFNsND6o?t=2188
一次性/不可重入:每次我们继续一个暂停的延续时,它的状态都会发生变化,我们不能从同一个暂停状态多次继续它(即我们不能回到过去)。这与可重入延续不同,每次我们暂停它们时,都会返回一个表示特定暂停点的新的不可变延续对象。即延续是一个时间点,每次我们继续它时,我们都会回到那个状态。可重入的延续严格来说比不可重入的更强大;即他们可以做一些完全不可能的事情,只需一次连续即可。
Cloneable:如果我们能够克隆一次性延续,我们可以提供与可重入延续相同的能力。即使每次我们继续它时延续都会发生变化,我们可以在继续创建该时间点的快照之前克隆它的状态,以便稍后返回。
Aiui continuations 没有直接暴露在 Raku 中,所以可能与 Raku 相关的正确答案(与 Rakudo 相对)是“没有延续”。但这对我来说并不清楚,所以在下文中,如果我很幸运,我会在其中描述我希望答案中的内容,我会假装在 Raku 的上下文中谈论它们是有道理的和乐堂是两个截然不同的领域。
这是我想象的那种答案是可能的(尽管我只是有点疯狂地猜测实际情况):
“作为“100 年”语言设计,Raku当前的底层语义 [执行?] 模型至少需要无 …
回到那天,我虽然明白了call/cc。这些天我看到了更多对“分隔”延续运算符的引用,它们似乎成对出现,如shift/ reset、prompt/ control,有时还有更奇特的。但我还没有看到任何基础知识的明确解释,所以
scheme continuations haskell functional-programming delimited-continuations
我正在研究Oleg和Asai划定的"傻瓜"续篇(http://pllab.is.ocha.ac.jp/~asai/cw2011tutorial/main-e.pdf),但本文使用移位/重置形式而不是奥列格的delimcc提供的提示材料.所以我有几个问题:
首先,什么是提示?为什么传下来shift和其他功能?知道什么是subcont也不错,但我愿意跳过这个,因为我只是想通过论文.此外,它们之间的区别是什么shift,shift0以及它们shift在论文中的对应方式.
另外,什么是resetdelimcc?我的直觉告诉我,new_prompt并push_prompt以某种方式对应reset.但我在这里也需要澄清一些.
编辑:我能够从论文中翻译一个简单的例子,我的直觉证明是正确的.但是我想要对这些差异进行真正的解释,为什么delimcc就是这样的.这是两个版本,以防任何人感兴趣
纸:
reset (fun () -> 3 + shift (fun _ -> 5 * 2) - 1)
Run Code Online (Sandbox Code Playgroud)
Delimcc:
let _ = let open Delimcc in
let np = new_prompt () in
push_prompt np (fun () -> 3 + (shift np (fun _ -> 5 * 2)) - 1)
Run Code Online (Sandbox Code Playgroud) continuations ocaml functional-programming delimited-continuations
我意识到这与通常的SO问题相反,但是即使我认为它不起作用,下面的代码也能正常工作.下面是一个小型Scala程序,它使用while循环的continuation.根据我对连续传递样式的理解,这段代码应该通过在while循环的每次迭代中向堆栈添加一个帧来产生堆栈溢出错误.但是,它工作得很好.
import util.continuations.{shift, reset}
class InfiniteCounter extends Iterator[Int] {
var count = 0
var callback: Unit=>Unit = null
reset {
while (true) {
shift {f: (Unit=>Unit) =>
callback = f
}
count += 1
}
}
def hasNext: Boolean = true
def next(): Int = {
callback()
count
}
}
object Experiment3 {
def main(args: Array[String]) {
val counter = new InfiniteCounter()
println(counter.next())
println("Hello")
println(counter.next())
for (i <- 0 until 100000000) {
counter.next()
}
println(counter.next())
}
}
Run Code Online (Sandbox Code Playgroud)
输出是:
1
Hello …Run Code Online (Sandbox Code Playgroud) 在尝试为ContT monad变换器构建一些直觉时,我(也许不出所料)发现自己很困惑.问题在于shiftT操作似乎没有做任何有用的事情.
首先是一个如何使用它的简单例子
shiftT $ \famr -> lift $ do
a <- calculateAFromEnvironment
famr a
Run Code Online (Sandbox Code Playgroud)
famr a只要它返回一些,就可能是一些更复杂的表达式m r.现在试图解释我对shiftT的直觉并没有增加任何东西:
-- inline shiftT
ContT (\f2 -> evalContT ((\f1 -> lift (do
a <- calculateAFromEnvironment
f1 a)) f2))
-- beta reduction
ContT (\f2 -> evalContT (lift (do
a <- calculateAFromEnvironment
f2 a)))
-- inline evalConT
ContT (\f2 -> runContT (lift (do
a <- calculateAFromEnvironment
f2 a)) return)
-- inline lift
ContT (\f2 -> runContT (ContT (\f3 -> (do
a <- …Run Code Online (Sandbox Code Playgroud)