2010-04-24 10 views
9

Dostałem aplet java do łączenia się i komunikowania za pomocą zastrzeżonego autobusu przy użyciu stylu opartego na oddzwanianiu. Obecnie wdrażam aplikację proof-of-concept w scala i próbuję ustalić, w jaki sposób mogę stworzyć nieco bardziej idiomatyczny interfejs scala.Czy mogę przekształcić ten asynchroniczny interfejs sieciowy Java w monadyczną reprezentację (lub coś innego idiomatycznego)?

Typowym (uproszczony) aplikacja może wyglądać to w 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(); 

w Scala mogę oczywiście zdefiniować niejawna konwersja z (T => Jednostki) w jego IListener, co z pewnością sprawia, że ​​rzeczy, bit łatwiejsze do odczytania:

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 
    }) 
}) 

Patrząc na to przypomniało mi obie obietnice scalaz i f # asynchroniczne przepływy pracy.

Moje pytanie jest takie:

mogę przekonwertować to do albo do zrozumienia lub coś podobnie idiomatyczne (czuję się jak to powinno map do aktorów dość dobrze też)

Idealnie chciałabym zobaczyć coś takiego:

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

Odpowiedz

6

Jeśli chcesz użyć for zrozumienie dla tego, polecam patrząc na Scala Language Specification dla jak dla listowe są rozszerzane do map, flatMap itp To daje pewne wskazówki o tym, jak ta struktura odnosi się do tego, co już masz (z zagnieżdżonymi połączeniami do addListener). Następnie można dodać niejawną konwersję z typu zwrotnego wywołania waitForData na nowy typ z odpowiednimi metodami map, flatMap, itp., Które delegują do addListener.

Aktualizacja

myślę, że można użyć scala.Responder[T] z biblioteki standardowej:

Zakładając klasę z addListener nazywa 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 
    }) 
} 

można następnie wykorzystać to jako żądanie

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

Zobacz i this presentation na temat korzystania z Responder[T] dla aplikacji czatu Comet.

+1

Scalaz dostarcza 'Monad [Responder]', więc legalnie masz instancję monady, jeśli robisz to, co sugeruje Ben Lings. Ponadto "Odpowiadający" jest rodzajem "uniwersalnej monady", ponieważ można zaimplementować dowolną inną monadę. – Apocalisp

+0

Odpowiadający dał mi dokładnie prawidłowe zachowanie, chociaż z jakiegoś powodu musiałem użyć 'def onEvent (t: T) = k (t)' zamiast tylko '= k' – AlecZorab

3

mam bardzo małe doświadczenie Scala, ale gdybym wdrażaniu coś takiego bym spojrzeć na wykorzystanie mechanizmu aktor zamiast używać klas zwrotna słuchacza. Aktorzy zostali stworzeni do komunikacji asynchronicznej, ładnie oddzielają te różne części aplikacji. Możesz również wysyłać wiadomości do wielu odbiorców.

Będziemy musieli poczekać na "prawdziwego" programistę Scala, aby ten pomysł wypalić. ;)

Powiązane problemy