2010-04-24 18 views
9

我已经给出了一个java api,用于连接并使用基于回调的风格通过专用总线进行通信。我目前正在scala中实现一个概念验证应用程序,我正在努力研究如何生成一个稍微更习惯的scala接口。我可以将这个异步java网络API转换为monadic表示形式吗?

典型(简体)应用程序可能看起来在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 
    }) 
}) 

看着这让我想起了斯卡拉承诺和f#异步工作流程。

我的问题是这样的:

我可以转换到这一点无论是对于理解或一些类似的习惯(我觉得这应该映射到角色相当不错太)

理想我想看看是这样的:

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

回答

6

如果你想使用for理解这一点,我建议你看Scala语言规范如何为内涵扩展到mapflatMap等,这会给你如何这种结构的一些线索涉及到你已经得到的(嵌套调用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 
)() 

请参阅the Scala wikithis presentation关于使用Responder[T]进行Comet聊天应用程序。

+1

Scalaz提供了'Monad [Responder]',所以如果你按照Ben Lings的建议,你可以合法地拥有一个monad实例。另外,'Responder'是一种“通用monad”,你可以在其中实现任何其他monad。 – Apocalisp 2010-04-25 18:22:09

+0

响应者给了我正确的行为,虽然由于某种原因我不得不使用'def onEvent(t:T)= k(t)'而不是'= k' – AlecZorab 2010-04-26 09:47:45

3

我很少斯卡拉经验,但如果我喜欢这个东西实现我期待利用演员的机制,而不是使用回调监听器类。参与者是为了异步通信而制作的,他们很好地将你应用程序的不同部分分开。你也可以让他们发送消息给多个听众。尽管如此,我们不得不等待一个“真正的”Scala程序员来充实这个想法。 ;)

相关问题