Я могу преобразовать этот асинхронный сетевой API Java в одноместное представление (или что-то еще идиоматическое)?

Мне дали API Java для соединения с и передачи по собственной шине с помощью основанного на обратном вызове стиля. Я в настоящее время реализовываю приложение подтверждения концепции в scala, и я пытаюсь разработать, как я мог бы произвести немного больше идиоматического интерфейса scala.

Типичное (упрощенное) приложение могло бы выглядеть примерно так в Java:

    DataType type = new DataType();
    BusConnector con = new BusConnector();
    con.waitForData(type.getClass()).addListener(new IListener<DataType>() {
        public void onEvent(DataType t) {
            //some stuff happens in here, and then we need some more data
            con.waitForData(anotherType.getClass()).addListener(new IListener<anotherType>() {
                public void onEvent(anotherType t) {
                    //we do more stuff in here, and so on
                }
            });
        }
    });

    //now we've got the behaviours set up we call
    con.start();

В scala я могу, очевидно, определить неявное преобразование из (T => Единица) в IListener, который, конечно, делает вещи немного более простыми читать:

implicit def func2Ilistener[T](f: (T => Unit)) : IListener[T] = new IListener[T]{
  def onEvent(t:T) = f
}

val con = new BusConnector
con.waitForData(DataType.getClass).addListener( (d:DataType) => {
  //some stuff, then another wait for stuff
  con.waitForData(OtherType.getClass).addListener( (o:OtherType) => {
    //etc
  })
})

Рассмотрение этого напомнило мне и об обещаниях scalaz и о f# асинхронных рабочих процессах.

Мой вопрос - это:

Я могу преобразовать это или в для понимания или в чего-то столь же идиоматического (я чувствую, что это должно отобразиться на агентов обоснованно хорошо также),

Идеально я хотел бы видеть что-то как:

for(
  d <- con.waitForData(DataType.getClass);
  val _ = doSomethingWith(d);
  o <- con.waitForData(OtherType.getClass)
  //etc
)
9
задан Apocalisp 25 April 2010 в 18:22
поделиться

2 ответа

Если вы хотите использовать для понимания для этого, я бы порекомендовал посмотреть в Спецификации языка Scala, чтобы узнать, как расширен до map , flatMap и т. д. Это даст вам некоторые подсказки о том, как эта структура соотносится с тем, что у вас уже есть (с вложенными вызовами к addListener ). Затем вы можете добавить неявное преобразование из возвращаемого типа вызова waitForData в новый тип с соответствующими методами map , flatMap и т. Д., Которые делегируют addListener .

Обновление

Думаю, вы можете использовать scala.Responder [T] из стандартной библиотеки:

Предполагая, что класс с addListener называется Dispatcher [T] :

trait Dispatcher[T] {
  def addListener(listener: IListener[T]): Unit
}

trait IListener[T] {
  def onEvent(t: T): Unit
} 

implicit def dispatcher2Responder[T](d: Dispatcher[T]):Responder[T] = new Responder[T} {
  def respond(k: T => Unit) = d.addListener(new IListener[T] {
    def onEvent(t:T) = k
  })
}

Затем вы можете использовать это по запросу

for(
  d <- con.waitForData(DataType.getClass);
  val _ = doSomethingWith(d);
  o <- con.waitForData(OtherType.getClass)
  //etc
) ()

См. вики Scala и эту презентацию об использовании Responder [T] для приложения чата Comet.

6
ответ дан 4 December 2019 в 21:48
поделиться

У меня очень мало опыта работы со Scala, но если бы я реализовал что-то вроде этого, я бы попытался использовать механизм акторов, а не использовать классы прослушивателей обратного вызова. Актеры созданы для асинхронной коммуникации, они прекрасно разделяют для вас разные части вашего приложения. Вы также можете заставить их отправлять сообщения нескольким слушателям.

Однако нам придется подождать, пока «настоящий» программист на Scala воплотит эту идею в жизнь. ;)

3
ответ дан 4 December 2019 в 21:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: