正确使用可变/不可变列表

Jen*_* K. 16 functional-programming scala immutability

目前,我试图理解Scala中的功能编程,我遇到了一个我无法弄清楚的问题.

想象一下以下情况:

你有两个类:ControllerBot.甲博特是由一个启动的独立演员控制器,做一些昂贵的操作,并将结果返回到控制器.因此,控制器的目的很容易描述:实例化Bot的多个对象,启动它们并接收结果.

到现在为止还挺好; 我可以在不使用任何可变对象的情况下实现所有这些.

但是我该怎么做,如果我必须存储Bot返回的结果,以后再用作另一个Bot的输入(后来意味着我不知道什么时候在编译时!)?

使用可变列表或集合执行此操作相当容易,但我在代码中添加了许多问题(因为我们在这里处理并发).

遵循FP范例,是否可以通过安全地使用不可变对象(列表...)来解决这个问题?

顺便说一句,我是FP新手,所以这个问题可能听起来很愚蠢,但我无法弄清楚如何解决这个问题:)

Dan*_*ral 7

演员通常有内部状态,本身就是可变的野兽.请注意,actor不是FP的东西.

您描述的设置似乎依赖于可变控制器,并且很难在默认情况下使用非严格的语言来解决它.但是,根据你的工作,你可以依靠未来.例如:

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())
Run Code Online (Sandbox Code Playgroud)

在这种情况下 - 因为!!返回Future- v1,v2并将v3并行计算.该消息Fn4作为参数接收应用的期货,这意味着它将等到所有值在开始计算之前计算出来.

同样,只有v4在计算后才会发送回复,因为未来也已应用.

实现这些功能的一种非常实用的方法是功能性反应式编程,或简称FRP.它与演员不同.

然而,Scala的美妙之处在于,您可以将这些范例结合到更适合您的问题的范围内.


Ale*_*nov 6

这就是类似Erlang的演员在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
Run Code Online (Sandbox Code Playgroud)