Jen*_* K. 16 functional-programming scala immutability
目前,我试图理解Scala中的功能编程,我遇到了一个我无法弄清楚的问题.
想象一下以下情况:
你有两个类:Controller和Bot.甲博特是由一个启动的独立演员控制器,做一些昂贵的操作,并将结果返回到控制器.因此,控制器的目的很容易描述:实例化Bot的多个对象,启动它们并接收结果.
到现在为止还挺好; 我可以在不使用任何可变对象的情况下实现所有这些.
但是我该怎么做,如果我必须存储Bot返回的结果,以后再用作另一个Bot的输入(后来意味着我不知道什么时候在编译时!)?
使用可变列表或集合执行此操作相当容易,但我在代码中添加了许多问题(因为我们在这里处理并发).
遵循FP范例,是否可以通过安全地使用不可变对象(列表...)来解决这个问题?
顺便说一句,我是FP新手,所以这个问题可能听起来很愚蠢,但我无法弄清楚如何解决这个问题:)
演员通常有内部状态,本身就是可变的野兽.请注意,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的美妙之处在于,您可以将这些范例结合到更适合您的问题的范围内.
这就是类似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)