Pergunta

Suponha que eu tenha de escrever algum código GUI da seguinte forma:

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

Como você escreve ele em CPS de estilo usando fones de ouvido Scala continuações?

Foi útil?

Solução

Apenas queria dar exemplo de trabalho, além de outras respostas.Com Scala continuações pode ter esta aparência:

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))
}

Este código, na verdade, compila e executa, de modo que você pode tentar fazer o mesmo.Você deve receber a seguinte saída:

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

Se você vai compilar este exemplo e, em seguida, não se esqueça de habilitar a continuação fornecendo -P:continuations:enable argumento para o compilador do Scala.

Outras dicas

A ponto de ter continuações é a capacidade de usar directa de um estilo de codificação, mesmo se, normalmente, eu seria forçado a código mais difícil de usar (por exemplo, em um evento orientado estilo).

Assim, o código de cliente que eu ia querer ser capaz de escrever seria assim:

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

Então escuta material seria escondido de mim.Mas, é claro, os ouvintes ainda teria que estar em algum lugar por baixo.Eu ocultá-los no widget do waitForEvent() método (acrescentado para a classe Widget ou disponíveis por meio de uma conversão implícita).O método de como seria:

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

Esta é, pelo menos no nível conceitual.Para chegar a este trabalho, você precisará adicionar algumas de tipo e/ou @cps anotações, provavelmente.

Aqui está um simples exemplo de trabalho:

reset{
  shift { (k: Unit => Unit) => widget1 addListener(handle1 _ andThen k)}
  shift { (k: Unit => Unit) => widget2 addListener(handle2 _ andThen k)}
  widget3 addListener(handle3 _)
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top