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:enableこの例をコンパイルする場合は、Scalaコンパイラーの引数を指定して継続を有効にすることを忘れないでください。

于 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()メソッドでそれらを非表示にします(Widgetクラスに追加されるか、暗黙の変換を通じて利用可能になります)。メソッドは次のようになります。

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

これは、少なくとも概念レベルではあります。これを機能させるには、おそらくいくつかのtype-および/または@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 に答える