Man*_*dha 8 functional-programming scala companion-object
在尝试理解伴随对象时,我编写了以下代码来计算类实例化的次数.我不得不使用'var'来保持计数.是否存在实现相同任务的"函数式编程"方法,即使用不可变变量.
class C {
C.counter+=1
def someCFunction = {println ("some C function. Counter is "+C.counter)}
}
object C{
var counter:Int=0 //I do not want to use var
}
val c1 = new C
c1.someCFunction
val c2 = new C
c2.someCFunction
Run Code Online (Sandbox Code Playgroud)
纯函数式程序避免可变变量和其他副作用的一个重要特性是表达式求值的值仅取决于表达式本身.它不依赖于评估事物的顺序(从左到右,从右到左,严格,懒惰),操作系统的状态,时间等.
特别是,这意味着在纯函数设置中,每次调用都new C将返回一个完全相同的计数器对象.这通常是一件好事,因为它可以更容易推理您的程序,但它会妨碍您尝试在那里做的事情.为了使C对象不同,你需要明确地传递他们的计数器值,说实话,这只是在地毯下扫除问题.
val c1 = new C(0)
val c2 = new C(1)
Run Code Online (Sandbox Code Playgroud)
如果你想拥有一个像内部类变量一样的全局"计数器"变量,你在一个纯功能设置中使用一种可能的方法来实现它,那就是将计数器值传递给需要计数器的每个函数,并使这些函数也返回计数器的更新版本.举个简短的例子:
def increment_counter(n: Int): Int = { n + 1)
def create_c(n: Int): (C, Int) = {
val c = new C(n)
val n' = increment_counter n
(c, n')
}
val n = 0
val (c1, n') = create_c(n)
val (c2, n'') = create_c(n')
val n' = increment_counter(n)
Run Code Online (Sandbox Code Playgroud)
你可以使用State Monad模式更好地构建它(对monad的大多数介绍可能会以此为例).
但是,它很可能最终会比仅使用计数器的可变变量更复杂.实际上,我通常在函数式语言中使用可变变量用于这些"全局递增计数器",这样我就可以这样做.
这是 State Monad 的一个很好的用例。您不是在原地修改变量,而是创建一个新值并将其传递。
import cats.data.State
class C {}
object C { val counter: State[Int, Unit] = State.pure() }
def createNewC: State[Int, C] = {
// increment the count, and return a new instance of C
C.counter.modify(_ + 1).map(_ => new C)
}
val countAll = for {
c0 <- createNewC
c1 <- createNewC
c2 <- createNewC
c3 <- createNewC
} yield {
// use your instance of C in here
()
}
// actually run your program, start the counter at 0
countAll.run(0).value._1 // 4
Run Code Online (Sandbox Code Playgroud)
注意:这里的状态来自 Cats 项目。