类似于函数式 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)
我想创建一个模拟模型来学习 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)