views:

200

answers:

2

At the moment, Im trying to understand Functional Programming in Scala and I came across a problem I cannot figure out myself.

Imagine the following situation:

You have two classes: Controller and Bot. A Bot is an independent Actor which is initiated by a Controller, does some expensive operation and returns the result to the Controller. The purpose of the Controller is therefore easy to describe: Instantiate multiple objects of Bot, start them and receive the result.

So far, so good; I can implement all this without using any mutable objects.

But what do I do, if I have to store the result that a Bot returns, to use it later as input for another Bot (and later on means that I don't know when at compile time!)?

Doing this with a mutable list or collection is fairly easy, but I add a lot of problems to my code (as we are dealing with concurrency here).

Is it possible, following the FP paradigm, to solve this by using immutable objects (lists...) safely?

BTW, im new to FP, so this question might sound stupid, but I cannot figure out how to solve this :)

+7  A: 

Actors usually have internal state, being, themselves, mutable beasts. Note that actors are not a FP thing.

The setup you describe seems to rely on a mutable controller, and it is difficult to get around it in a language that is not non-strict by default. Depending on what you are doing, though, you could rely on futures. For example:

case Msg(info) =>
  val v1 = new Bot !! Fn1(info)
  val v2 = new Bot !! Fn2(info)
  val v3 = new Bot !! Fn3(info)
  val v4 = new Bot !! Fn4(v1(), v2(), v3())
  reply(v4())

In this case -- because !! returns a Future -- v1, v2 and v3 will be computed in parallel. The message Fn4 is receiving as parameters the futures applied, meaning it will wait until all values are computed before it starts computing.

Likewise, the reply will only be sent after v4 has been computed, as the future has been applied for as well.

A really functional way of doing these things is the functional reactive programming, or FRP for short. It is a different model than actors.

The beauty of Scala, though, is that you can combine such paradigms to the extent that better fits your problem.

Daniel
Thanks first of all, the "Future" thing is new to me and I will look into it, although I think that it might not really help me.. But, I will first of all have a look into FRP which may be the answer to all my problems ( since I want to learn FP, not the usage of Actors :) )
Jens K.
"and it is difficult to get around it in a language that is not non-strict by default" You can just do what Erlang does: pass the state as a parameter to a tail-recursive function.
Alexey Romanov
@Alexey I'm not sure exactly how that would work. Why not provide an answer with an example?
Daniel
@Daniel I gave an example.
Alexey Romanov
+6  A: 

This is how an Erlang-like actor could look in Scala:

case class Actor[State](val s: State)(body: State => Option[State]) { // immutable
  @tailrec
  def loop(s1: State) {
    body(s1) match {
      case Some(s2) => loop(s2)
      case None => ()
    }
  }

  def act = loop(s)
}

def Bot(controller: Actor) = Actor(controller) { 
  s => 
    val res = // do the calculations
    controller ! (this, res)
    None // finish work
} 

val Controller = Actor(Map[Bot, ResultType]()) {s =>
  // start bots, perhaps using results already stored in s
  if ( 
    // time to stop, e.g. all bots already finished 
  )
    None
  else
    receive {
      case (bot, res) => Some(s + (bot -> res)) // a bot has reported result
    }
}

Controller.act
Alexey Romanov
Thanks for this answer. I played around with your example and altered it to my needs, and it seems to be the perfect solution to my specific problem!
Jens K.