一.本章要点

  • 延续让你可以回到程序执行当中之前的某个点;
  • 可以在shift块中捕获延续
  • 延续函数一直延展到包含它的reset块的尾部
  • 延续所谓的”余下的运算“,从包含shift的表达式开始,到包含它的reset块的尾部结束,其中shift替换成一个”洞“
  • 当你传入一个参数来调用延续时,这个”洞“将传入的参数值填上
  • 包含shift表达式的代码将被以”延续传递风格“(CPS)重写,直到包含该延续的reset为止
  • 包含shift但没有reset的方法必须加上CPS注解
  • 延续可以用来将对某个树形结构的递归访问变成迭代
  • 延续可以在Web或GUI应用中撤销”控制反转“  

二.捕获并执行延续

  延续是一种让你回到程序之前的一个点的一种机制。使用shift结构:

//这里的延续是一个不带参数也不带返回值的函数
执行延续即简单调用cont就跳回shift中那一点
var cont:(Unit=>Unit)=null
...
shift{k:(Unit=>Unit)=>//延续被传递给了shift
cont=k //保存下来,以便以后使用
}
//在Scala中,延续是定界的——只能延续到指定的边界,这个边界由reset{...}标出,调用cont时,执行从shift开始,一直延展到reset块的边界
reset{
...
shift{
k:(Unit=>Unit)=>cont=k
}//对cont的调用将从这儿开始
}//...结束

  完整读取文件的例子:

Scala学习二十二——定界延续-LMLPHP

三.”运算当中挖个洞“

  延续捕获了什么:把shift块想象成一个位于reset块中的洞。当执行延续时,可以将一个值传入到这个洞中,运算继续,就像shift本就是那个值。。。

四.reset和shift的控制流传

  双重职责——定义延续职责和捕获延续函数。

  调用reset,代码体开始执行,执行遇到shift,shift的代码体被调用,传入延续参数作为参数,当shift执行完成,执行立即跳转到包含延续的reset末尾。。。    

五.reset表达式的值

  如果reset块退出是因为执行了shift,那么得到的值就是shift块的值;如果reset块执行到自己的末尾的话,值就是reset的值(块中最后一个表达式的值);在实际操作,如果reset代码块包含分支或循环,两种情况都可能。    

六.reset和shift表达式的类型

  reset和shift都是带有类型参数的方法。。。

七.CPS注解

   某些虚拟机延续的实现方式是抓取运行期栈的快照。当有人调用延续时,运行期栈被恢复成快照的样子(Java虚拟机不允许对栈进行操作)。

  为了在JVM提供延续,Scala对reset块中的代码进行”延续风格“(CPS)的变换。

八.将递归访问转化为迭代

  reset和shift方法适合控制流转的模式。每当shift被执行,程序就退出包含它的reset。当被捕获的延续中被调用时,程序又返回shift的位置。。。

九.撤销控制反转

  。。。

十.CPS变换

  。。。

十一.转换嵌套的控制上下文

  。。。

十二.练习

  Scala学习二十二——定界延续-LMLPHP

Scala学习二十二——定界延续-LMLPHP

Scala学习二十二——定界延续-LMLPHPScala学习二十二——定界延续-LMLPHPScala学习二十二——定界延续-LMLPHPScala学习二十二——定界延续-LMLPHP

05-08 08:23