简体   繁体   English

类似于功能 Scala 中的 for-loop

[英]Similar to for-loop in functional Scala

I want to create a simulation model to learn Scala as well as functional programming (FP).我想创建一个模拟 model 来学习 Scala 以及函数式编程(FP)。 I already have all the logic: creation of a population of agents (it's just a List[Agent] , where Agent is a class defining an individual member, like a particle in a gas) and some functions (moving in space, for example) that "act" on the population.我已经有了所有的逻辑:创建一组代理(它只是一个List[Agent] ,其中Agent是一个 class 定义一个单独的成员,就像气体中的粒子)和一些功能(例如在太空中移动)对人口的“行动”。

My problem comes when I want to apply the same functions over the initial population several times because of immutability in FP.由于 FP 中的不变性,当我想在初始总体上多次应用相同的函数时,我的问题就出现了。 I want to apply those functions to the initial population for N rounds (where a round is defined when all the functions have been applied).我想将这些函数应用于 N 轮的初始总体(在应用所有函数后定义一轮)。 I don't know how to deal with immutable values between rounds.我不知道如何处理轮次之间的不可变值。

Usually, I would do a for-loop where a variable changes its value, but how do you deal with this when values are immutable?通常,我会做一个 for 循环,其中一个变量会改变它的值,但是当值是不可变的时,你如何处理呢?

My code now looks like this:我的代码现在看起来像这样:

object Main extends App {
    val soc = Society(numAgents = 1000)        // Create a Society

    val agents = soc.initSociety()             // Init the society
    val movedAgents = soc.moveAgents(agents)   // Move the agents
}

The method are defined such that they return a List[Agent] , so the type is always the same.该方法被定义为返回List[Agent] ,因此类型始终相同。

I've seen some solutions using foldleft , but I need to apply the function moveAgents to what it returns.我见过一些使用foldleft的解决方案,但我需要将 function moveAgents 应用于它返回的内容。

You can get the return value of moveAgents with folds.您可以通过折叠获得moveAgents的返回值。 If you simply want to call the moveAgents method n times, you can do this如果你只是想调用moveAgents方法n次,你可以这样做

val newAgents = (1 to n).foldLeft(soc.initSociety()) { (a, i) => soc.moveAgents(a) }

This is the equivalent of doing soc.moveAgents(soc.moveAgents(...(soc.initSociety()))) with n calls to moveAgents这相当于在调用moveAgents时执行 soc.moveAgents(soc.moveAgents( n soc.moveAgents(soc.moveAgents(...(soc.initSociety())))

If you have multiple functions that you want to apply (with a different one each round), you can do the same thing:如果您有多个要应用的功能(每轮使用不同的功能),您可以执行相同的操作:

// n/3 because there are 3 functions
val newAgents = (1 to n/3).foldLeft(soc.initSociety()) { (a, i) => f3(f2(f1(a))) }

If you have, say, a List of functions, you can try this:如果你有一个函数List ,你可以试试这个:

val fs = List(f1, f2, f3)
val newAgents = (1 to (n/fs.size)).foldLeft(soc.initSociety()){ (a, i) => fs.foldLeft(a){ (ag, f) => f(ag) } }

Well any simple for loop can be easily rewritten as a tal-recursion, and a (tail) recursion can usually be written as a foldLeft .好吧,任何简单的 for 循环都可以很容易地重写为 tal 递归,而(尾)递归通常可以写为foldLeft

First approach, simple loop.第一种方法,简单循环。

def stimulate(soc: Society, n: Int): List[Agent] = {
  var agents = soc.initSociety()
  for (i <- 0 to n) {
    agents = soc.moveAgents(agents)
  }
  agents
}

Second approach, recursion.第二种方法,递归。
(let's remove that var) (让我们删除那个var)

def stimulate(soc: Society, n: Int): List[Agent] = {
  @annotation.tailrec
  def loop(i: Int, agents: List[Agent]): List[Agent] =
    if (i < n) loop(i + 1, agents = soc.moveAgents(agents))
    else agents

  loop(i = 0, agents = soc.initSociety())
}

Third approach, fold.第三种方法,折叠。
(let's remove the boilerplate from the recursion) (让我们从递归中删除样板)

def stimulate(soc: Society, n: Int): List[Agent] =
  (0 to n).foldLeft(soc.initSociety()) { case (agents, _) =>
    soc.moveAgents(agents)
  }

If the intermediate values between each round is of any interest...如果每轮之间的中间值有任何兴趣......

val rounds = List.iterate(agents, n)(f _ andThen g andThen h)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM