我可以将这个异步java网络API转换为monadic表示(或其他惯用语)吗?

Ale*_*rab 9 monads scala scalaz

我已经获得了一个java api,用于通过基于回调的样式连接和通过专用总线进行通信.我目前正在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();
Run Code Online (Sandbox Code Playgroud)

在scala中,我可以明确地定义从(T => Unit)到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
  })
})
Run Code Online (Sandbox Code Playgroud)

看着这个让我想起了scalaz promises和f#async工作流程.

我的问题是:

我可以将其转换为for comprehension或类似的惯用语(我觉得这应该合理地映射到演员)

理想情况下,我希望看到类似的东西:

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

Ben*_*ngs 6

如果你想使用for这个理解,我建议你看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
  })
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以按要求使用此功能

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

有关使用Comet聊天应用程序的信息,请参阅Scala wiki此演示文稿Responder[T].