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

时间:2010-04-24 16:04:04

标签: scala monads 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();

在scala中,我可以明确地定义从(T =&gt; 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
  })
})

这看起来让我想起了scalaz promises和f#async工作流程。

我的问题是:

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

理想情况下,我希望看到类似的内容:

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

2 个答案:

答案 0 :(得分:6)

如果您想对此使用for理解,我建议您查看Scala语言规范,了解如何将理解扩展为mapflatMap等。将为您提供有关此结构如何与您已经获得的内容相关的一些线索(嵌套调用addListener)。然后,您可以将waitForData调用的返回类型的隐式转换添加到具有委派给map的相应flatMapaddListener等方法的新类型。< / p>

<强>更新

我认为您可以使用标准库中的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
) ()

使用Responder[T]查看Comet聊天应用程序时,请参阅the Scala wikithis presentation

答案 1 :(得分:3)

我的Scala经验非常少,但如果我实现这样的东西,我会利用actor机制而不是使用回调监听器类。演员是为异步通信而制作的,他们很好地为您分离了应用程序的不同部分。您也可以让他们向多个听众发送消息。

我们必须等待一个“真正的”Scala程序员来充实这个想法。 ;)