10

イベント駆動型の意味を明確にするために、私が持っている状況を指しています

def onTrade(...)

特定の株が取引されるたびに呼び出されます。毎日の最高取引価格を追跡したいとします。私にとって明らかな解決策は次のとおりです。

var dailyHigh = 0

def onTrade(...) {
    if (price > dailyHigh) dailyHigh = price
}

var の代わりに val を使用してこの機能を実現する方法はありますか? また、将来、dailyLow、volumeHigh、volumeLow などを追加する可能性があると仮定します。

4

5 に答える 5

9

論文Deprecating the observer patternは興味深いかもしれませんが、そこに記述されているライブラリはまだ利用できないと思います。

于 2011-07-25T11:14:56.260 に答える
8

実際、それほど問題はありません。完全なソリューションでは、おそらくReader、IO、Stateモナドに加えて、Iterateeとレンズを使用しますが、より単純なバージョンを次に示します。

case class State(dailyHigh: Int = 0)

object Main {
  type Event = (State => State)

  def mainLoop(currState: State, events: Stream[Event]): State =
    if (events.nonEmpty) {
      val newState = events.head(currState)
      mainLoop(newState, events.tail)
    } else currState

  def onTrade(price: Int): Event = (s: State) =>
    if (price > s.dailyHigh) s.copy(dailyHigh = price) else s

  def main(args: Array[String]) {
    val events = onTrade(5) #:: onTrade(2) #:: onTrade(10) #:: onTrade(5) #:: Stream.empty
    val finalState = mainLoop(State(), events)
    println(finalState)
  }
}

ほら、まあ、変数はありません!

もちろん、状態は非常に複雑になる可能性がありますが、レンズの出番です。レンズを使用すると、任意の複雑なデータ構造を調べて変更(新しい値でコピー)するのは非常に簡単です。

反復子の使用はイベントにとって自然です。非常に単純な意味で、「onTrade」は、部分関数で構成されている場合、各イベントで列挙子(イベントを「生成」するもの)によって呼び出される反復子になります。すべてを折りたたむことができます。それらを単一の部分関数にまとめます。

または、状態モナドを内包表記のIOモナドと組み合わせることができます。

最後に、継続のオプションがあります。一部の処理で一連のイベントを受信する必要がある場合、各イベントの結果は継続になる可能性があり、継続自体が状態の一部になります。

于 2011-07-25T21:38:43.917 に答える
2

変更可能なステータスが自然に必要になる場合もあります。以下は、書籍「scala by example」の例です。
また、いくつかの変更可能な status(maxBid,maxBidder)もあります。したがって、var は必ずしも悪い考えではありません。うまくいく場合もあります。

   class Auction(seller: Actor, minBid: Int, closing: Date) extends Actor {
   val timeToShutdown = 36000000 // msec
   val bidIncrement = 10
   def act() {
      var maxBid = minBid - bidIncrement
      var maxBidder: Actor = null
      var running = true
      while (running) {
         receiveWithin((closing.getTime() - new Date().getTime())) {
            case Offer(bid, client) =>
               if (bid >= maxBid + bidIncrement) {
                  if (maxBid >= minBid) maxBidder ! BeatenOffer(bid)
                  maxBid = bid; maxBidder = client; client ! BestOffer
               } else {
                  client ! BeatenOffer(maxBid)
               }
            case Inquire(client) =>
               client ! Status(maxBid, closing)
            case TIMEOUT =>
               if (maxBid >= minBid) {
                  val reply = AuctionConcluded(seller, maxBidder)
                  maxBidder ! reply; seller ! reply
               } else {
                  seller ! AuctionFailed
               }
               receiveWithin(timeToShutdown) {
                  case Offer(_, client) => client ! AuctionOver
                  case TIMEOUT          => running = false
               }
         }
      }
   }
}
于 2011-07-25T11:02:27.527 に答える
0

そのタスクには、関数型リアクティブ プログラミングを強くお勧めします。scala でのそのようなライブラリに関するトークは次のとおりです: http://skillsmatter.com/podcast/scala/reactors

于 2011-07-25T11:24:51.187 に答える
0

実際に行ったことはありませんが、値を変更する代わりに、ストリームに新しいインスタンスを作成できました。

その後、他のプロセスはそのストリームを繰り返すことができ、ストリームの最後のインスタンス化された要素に到達したときに待機することになります。

于 2011-07-25T09:59:59.513 に答える