Мне дали 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
)
Если вы хотите использовать для
понимания для этого, я бы порекомендовал посмотреть в Спецификации языка 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.
У меня очень мало опыта работы со Scala, но если бы я реализовал что-то вроде этого, я бы попытался использовать механизм акторов, а не использовать классы прослушивателей обратного вызова. Актеры созданы для асинхронной коммуникации, они прекрасно разделяют для вас разные части вашего приложения. Вы также можете заставить их отправлять сообщения нескольким слушателям.
Однако нам придется подождать, пока «настоящий» программист на Scala воплотит эту идею в жизнь. ;)