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

发布于 2024-09-16 14:08:32 字数 543 浏览 7 评论 0原文

目前,我试图理解 Scala 中的函数式编程,但遇到了一个我自己无法解决的问题。

想象一下以下情况:

您有两个类:ControllerBot机器人是一个独立的Actor,由控制器启动,执行一些昂贵的操作并将结果返回给控制器。因此,控制器的目的很容易描述:实例化Bot的多个对象,启动它们并接收结果。

到目前为止,一切都很好;我可以在不使用任何可变对象的情况下实现这一切。

但是,如果我必须存储机器人返回的结果,以便稍后将其用作另一个机器人的输入(稍后意味着我不知道什么时候编译时!)?

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

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

顺便说一句,我是 FP 的新手,所以这个问题可能听起来很愚蠢,但我不知道如何解决这个问题:)

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

世界和平 2024-09-23 14:08:32

演员通常有内部状态,他们自己就是可变的野兽。请注意,演员不是 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 - v1v2v3 将并行计算。消息 Fn4 正在接收作为 future 应用的参数,这意味着它将等到所有值都计算完毕后才开始计算。

同样,只有在计算出 v4 后才会发送回复,因为 future 也已被应用。

执行这些操作的真正函数式方法是函数式响应式编程,简称 FRP。这是与演员不同的模型。

不过,Scala 的优点在于您可以将这些范例组合到更适合您的问题的程度。

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.

心舞飞扬 2024-09-23 14:08:32

这就是类似 Erlang 的 actor 在 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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文