Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Scala, how would I combine event driven programming with a functional approach?

To clarify what I mean by event driven I'm referring to a situation where I have

def onTrade(...)

Which is called every time a particular stock trades. Suppose I want to track the daily highest trade price. To me the obvious solution is:

var dailyHigh = 0

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

Is there a way to achieve this functionality using val instead of var? Assume also that I may want to add dailyLow, volumeHigh, volumeLow etc in the future.

like image 652
deltanovember Avatar asked Jul 25 '11 09:07

deltanovember


People also ask

Is functional programming event-driven?

In recent years, functional programming has become popular because of its suitability in concurrent, parallel, and event-driven programming. Most modern programming languages support functional programming styles.

What is event-driven programming and how is it different from functional programming?

The main difference between event-driven programming and other forms is in how you receive input. With an event-driven approach, much of your code is bundled into event handlers that sit around waiting for the event source to collect the data of an event and notify all handlers.

Which type of application is best suited to the use of event-driven programming?

Serverless is probably the most suitable platform to host event-driven applications. This is because event processing is very different from typical transaction processing. An event often only requires a simple response rather than complex processing.

Which are examples of an event that can be used in event-driven programming?

Events include mouse, computer keyboard, and user interface, which events have to be triggered in this program. This means the user has to interact with an object in this program, for example, click a button by a mouse, use the computer keyboard to choose a button, etc.


2 Answers

The paper Deprecating the observer pattern might be of interest, but I believe the library it describes is not available yet.

like image 120
Didier Dupont Avatar answered Sep 27 '22 18:09

Didier Dupont


Not much of a problem, actually. A full solution would probably use Reader, IO and State monads plus Iteratee and lenses, but here's a simpler version:

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

Look, ma, no vars!

State can become quite complex, of course, but that's where lenses come in. With lenses, it is pretty easy to consult and change (copy with new value) arbitrarily complex data structures.

Using iteratees is natural for events -- in a very simple sense, "onTrade" becomes an iteratee that gets invoked by an enumerator (the thing that "generates" the events) with each event if composed from partial function, you can fold all of them into a single partial function.

Alternatively, State monads can be combined with IO monads on for-comprehensions.

Finally, there's the option of continuations. If some processing requires a chain of events to be received, then the result of each event can be a continuation, and the continuation themselves become part of the state.

like image 26
Daniel C. Sobral Avatar answered Sep 27 '22 19:09

Daniel C. Sobral