类似于函数式 Scala 中的 for 循环

Similar to for-loop in functional Scala

我想创建一个模拟模型来学习 Scala 和函数式编程 (FP)。我已经有了所有的逻辑:创建一个代理群体(它只是一个 List[Agent],其中 Agent 是一个 class 定义一个单独的成员,就像气体中的一个粒子)和一些函数(例如 space 移动)"act" 对人口的影响。

我的 问题 当我想在初始种群上多次应用相同的函数时,因为 FP 中的不变性。我想将这些函数应用于 N 轮的初始种群(在应用所有函数后定义一轮)。我不知道如何处理回合之间的不可变值。

通常,我会做一个 for 循环,其中一个变量改变它的值,但是当值不可变时你如何处理这个?

我的代码现在看起来像这样:

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
}

方法定义为 return 和 List[Agent],因此类型始终相同。

我见过一些使用 foldleft 的解决方案,但我需要将函数 moveAgents 应用到它 returns.

你可以得到 moveAgents 的 return 值。如果你只是想调用moveAgents方法n次,你可以这样做

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

这相当于 soc.moveAgents(soc.moveAgents(...(soc.initSociety()))) 调用 n moveAgents

如果您有多个要应用的函数(每轮一个不同的函数),您可以做同样的事情:

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

如果你有,比如说,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) } }

好吧,任何简单的 for 循环都可以很容易地重写为 tal 递归,而 (tail) 递归通常可以写成 foldLeft.

第一种方法,简单循环。

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

第二种方法,递归。
(让我们删除那个变量)

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())
}

第三种方法,弃牌。
(让我们从递归中删除样板文件)

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

如果每轮之间的中间值有任何意义...

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