用 Continuation 先把简单的事情搞复杂 , 再用 Continuation Monad 把复杂的事情搞简单 .
1. 问题 :
假如我们要对一个表达式求值 : 3*7+9+12
我们先定义 2 个函数 :
def add(i: Int , j: Int ) = i+j
def multi(i: Int ,j: Int ) = i*j
然后用这 2 个函数求这个表达式的值 : 实现 1
val v1 = multi(3,7)
val v2 = add (v1, 9)
val v3 = add (v2, 12)
//return 42
2. 先看看怎样用 Continuations 把简单的事情搞复杂
我们先定义 2 个带 Continuations 的函数 :
def addc[A](i: Int , j: Int ,f:( Int =>A)):A=f(i+j)
def multic[A](i: Int , j: Int , f:( Int =>A)):A = f(i*j)
我们为每个函数增加了一个输入参数 , 一个 Continuation - f
然后用这 2 个函数求这个表达式的值 : 实现 2
val vc1 = multic(3,7,{x=>addc(x,9,{y=>addc(y,12,{z=>z})})})
//return 42
实现 2 读起来比起实现 1 要头大得多 .
3. 为什么带 continuation 的函数难读
带 continuation 的函数把 evaluate 的过程颠倒了 . 比如 : println(add(4,5)) 我们知道它的 evaluate 次序是
a. 先求 add(4,5)
b. 再通过 println 输出结果到 stdout
而 addc(4,5,println) 的 evaluate 次序和 println(add(4,5)) 一样 , 但写法完全相反 , 容易造成大脑错乱 .
4. 怎样读带 continuation 的函数
a. 从左向右
b. Continuation 中的输入变量是上个计算的结果 . 如 : 在 val vc1 = multic(3,7,{x=>addc(x,9,{y=>addc(y,12,{z=>z})})}) 中 , 把 Continuation 中的输入变量用上个计算的结果代替 , 如 x 等于 3*7, y=3*7+9, z=3*7+12
5. 再用 Continuation Monad 把复杂的事情搞简单
用 scala2.8 的 shift/reset 实现表达式 ( 实现 3)
记得 import scala.continuations.ControlContext._
val r = reset{
val s = shift{
k:( Int => Int ) => k(3)
}
val v1 = multi(s,7)
val v2 = add(v1,9)
val v3 = add(v2,12)
v3
}
scala2.8 的 shift/reset 本质上是一个 continuation monad
看上去和实现 1 相似了 .