在Scala中,我如何将事件驱动编程与功能方法相结合?

del*_*ber 9 scala event-driven

为了澄清事件驱动我的意思,我指的是我所处的情况

def onTrade(...)
Run Code Online (Sandbox Code Playgroud)

每次特定股票交易时都会调用.假设我想跟踪每日最高交易价格.对我来说,明显的解决方案是:

var dailyHigh = 0

def onTrade(...) {
    if (price > dailyHigh) dailyHigh = price
}
Run Code Online (Sandbox Code Playgroud)

有没有办法使用val代替var来实现这个功能?还假设我可能希望将来添加dailyLow,volumeHigh,volumeLow等.

Did*_*ont 9

论文弃用观察者模式可能是有意义的,但我相信它所描述的库尚不可用.


Dan*_*ral 7

实际上并不是什么大问题.一个完整的解决方案可能会使用Reader,IO和State monads以及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)
  }
}
Run Code Online (Sandbox Code Playgroud)

看,妈,没有变形!

当然,状态可能变得非常复杂,但这就是镜头的用武之地.使用镜头,可以很容易地查询和更改(复制新值)任意复杂的数据结构.

使用iteratees对于事件来说很自然 - 在一个非常简单的意义上,"onTrade"成为一个由枚举器调用的迭代器("生成"事件的东西),如果由部分函数组成,则可以折叠所有事件他们分成一个部分功能.

或者,State monads可以与IO monads结合使用以进行理解.

最后,还有延续选项.如果某些处理需要接收一系列事件,那么每个事件的结果可以是延续,并且延续本身也成为状态的一部分.

  • @MPT Newness当然扮演着一个角色 - 可能是一个重要的角色.但这不仅仅是......这些东西都是抽象的,因此,它们统一了许多不习惯的程序员心中不同的东西,并且隐藏了细节_.处理抽象概念比处理具体事情更难.至于更好,它使程序更易于组合,更容易测试.但是当你看一些小例子时,它似乎不合适. (2认同)