5

假设我必须编写一些 GUI 代码,如下所示:

widget1.addListener(event1 =>
   handle1(event1)
   widget2.addListener(event2 =>
     handle2(event2)
     widget3.addListener(event3 => handle3(event3))
   )
)

您将如何使用 Scala 延续以 CPS 风格编写它?

4

3 回答 3

8

除了其他答案之外,只想提供工作示例。使用 Scala 延续,它看起来像这样:

import scala.util.continuations._

object ContinuationsExample extends App {
  val widget1 = Widget()
  val widget2 = Widget()

  reset {
    val event1 = widget1.getEvent
    println("Handling first event: " + event1)
    val event2 = widget2.getEvent
    println("Handling second event: " + event2)
  }

  widget2 fireEvent Event("should not be handled")
  widget1 fireEvent Event("event for first widget")
  widget2 fireEvent Event("event for second widget")
  widget1 fireEvent Event("one more event")
}

case class Event(text: String)

case class Widget() {
  type Listener = Event => Unit
  var listeners : List[Listener] = Nil

  def getEvent = shift { (l: Listener) =>
    listeners = l +: listeners
  }

  def fireEvent(event: Event) = listeners.foreach(_(event))
}

这段代码实际上是编译运行的,大家可以自己试试。您应该收到以下输出:

Handling first event: Event(event for first widget)
Handling second event: Event(event for second widget)
Handling first event: Event(one more event) 

如果您要编译此示例,请不要忘记通过为-P:continuations:enableScala 编译器提供参数来启用延续。

于 2011-05-19T21:53:57.040 回答
3

延续的关键在于能够使用直接的编码风格,即使通常我会被迫以更难使用的方式(例如事件驱动的风格)进行编码。

所以我希望能够编写的客户端代码是这样的:

reset {
    val event1 = widget1.waitForEvent()
    handle1(event1)
    val event2 = widget2.waitForEvent()
    handle2(event2)
    val event3 = widget3.waitForEvent()
    handle3(event3)
}

所以听众的东西会对我隐藏。但是当然,听众仍然必须在下面的某个地方。我会将它们隐藏在小部件的 waitForEvent() 方法中(添加到小部件类或通过隐式转换可用)。该方法如下所示:

def waitForEvent() = shift { k =>
    this.addListener(event => k(event))
    k
}

这至少是在概念层面。要使其正常工作,您可能需要添加一些类型和/或@cps 注释。

于 2011-05-19T21:18:04.560 回答
1

这是一个简单的工作示例:

reset{
  shift { (k: Unit => Unit) => widget1 addListener(handle1 _ andThen k)}
  shift { (k: Unit => Unit) => widget2 addListener(handle2 _ andThen k)}
  widget3 addListener(handle3 _)
}
于 2011-05-19T19:52:09.287 回答