目前,我试图理解Scala中的函数式编程,我遇到了一个我自己无法弄清楚的问题。
想象一下以下情况:
您有两个类: Controller 和 Bot 。 Bot 是一个独立的Actor,由 Controller 启动,执行一些昂贵的操作并将结果返回给 Controller 。因此, Controller 的目的很容易描述:实例化 Bot 的多个对象,启动它们并接收结果。
到目前为止,这么好;我可以在不使用任何可变对象的情况下实现所有这些。
但我该怎么做,如果我必须存储 Bot 返回的结果,以后再将其用作另一个 Bot 的输入(稍后意味着我不知道什么时候在编译时!)?
使用可变列表或集合执行此操作相当容易,但我在代码中添加了很多问题(因为我们在这里处理并发)。
遵循FP范例,是否有可能通过安全地使用不可变对象(列表...)来解决这个问题?
顺便说一句,我是FP新手,所以这个问题可能听起来很愚蠢,但我无法弄清楚如何解决这个问题:)答案 0 :(得分:7)
演员通常有内部状态,本身就是可变的野兽。请注意,演员不是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())
在这种情况下 - 因为!!
返回Future
- v1
,v2
和v3
将并行计算。消息Fn4
正在接收所应用的期货作为参数,这意味着它将等到所有值在计算开始之前计算出来。
同样,只有在计算v4
后才会发送回复,因为未来也已应用。
实现这些功能的一个非常实用的方法是功能反应式编程,或简称FRP。它与演员不同。
然而,Scala的美妙之处在于,您可以将这些范例结合到更适合您的问题的范围内。
答案 1 :(得分: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