Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

返回操作

(Return Operations)

在之前的 emit-collect 示例中,我们看到了 return 返回操作的使用。这种操作会改变处理器动作(action)的最终结果。例如,考虑我们之前使用的自定义异常效应 raise。我们可以定义一个带泛型的处理器,将任何异常动作转换为返回一个 maybe 类型的动作:

fun raise-maybe( action : () -> <raise|e> a ) : e maybe<a>
  with handler
    return(x)      Just(x)   // normal return: wrap in Just
    ctl raise(msg) Nothing   // exception: return Nothing directly
  action()


fun div42()
  (raise-maybe{ safe-divide(1,0) }).default(42)

(div42的函数体脱糖后为 default( raise-maybe(fn(){ safe-divide(1,0) }), 42 ))

一个起名为 state 的效应

为了更全面地了解返回操作的用法,我们来看一下一个起名为 state 的效应,表示一种状态访问方式。在最一般的形式下,它仅包含一个设置(set)操作和一个获取(get)操作:

effect state<a>
  fun get() : a
  fun set( x : a ) : ()

fun sumdown( sum : int = 0 ) : <state<int>,div> int
  val i = get()
  if i <= 0 then sum else
    set( i - 1 )
    sumdown( sum + i )

我们可以通过使用 var 声明来最简便地定义一个带泛型的状态处理器:

fun state( init : a, action : () -> <state<a>,div|e> b ) : <div|e> b
  var st := init
  with handler
    fun get()  st
    fun set(i) st := i
  action()

其中 state(10){ sumdown() } 的求值结果为 55。

在前一个状态示例的基础上,假设我们还希望返回最终状态。一种简洁的做法是再次利用返回操作,将最终结果与最终状态配对在一起:

fun pstate( init : a, action : () -> <state<a>,div|e> b ) : <div|e> (b,a)
  var st := init
  with handler
    return(x)  (x,st)       // pair with the final state
    fun get()  st
    fun set(i) st := i
  action()

其中 pstate(10){ sumdown() } 求值结果为 (55, 0)。


高级

甚至有可能定义一个只包含返回操作的处理程序:这样的处理程序完全不处理任何效应,而仅仅转换函数的最终结果。例如,我们可以用单独的返回处理程序来定义前面的示例,如下所示:

fun pstate2( init : a, action : () -> <state<a>,div|e> b ) : <div|e> (b,a)
  var st := init
  with return(x) (x,st)
  with handler
    fun get()  st
    fun set(i) st := i
  action()

这里有点牵强,但它可以使某些程序的定义更加简洁,例如[5]。