如何在函数式编程中实现setter?我希望尊重不可变性和其他函数式编程原则。
private int age;
public void setAge(int age){
this.age=age;
}
这是否可能?如果不行,那么在函数式编程语言中如何表示程序的状态(及其变化)?
private int age;
public void setAge(int age){
this.age=age;
}
这是否可能?如果不行,那么在函数式编程语言中如何表示程序的状态(及其变化)?
一般来说,您应该创建一个新状态而不是修改旧状态。
您可以像这样使用copy
方法:
case class Person(name: String, age: Int)
val youngBob = Person("Bob", 15)
val bob = youngBob.copy(age = youngBob.age + 1)
// Person(Bob,16)
您也可以使用Lens
:
import scalaz._, Scalaz._
val ageLens = Lens.lensu[Person, Int]( (p, a) => p.copy(age = a), _.age )
val bob = ageLens.mod(_ + 1, youngBob)
// Person(Bob,16)
请参见Learning scalaz/Lens。还有其他的Lens
实现。
例如,您可以使用shapeless
Lens
,该Lens
使用宏实现,因此您不必手动创建Lens
:
import shapeless._
val ageLens = Lens[Person] >> 1
val bob = ageLens.modify(youngBob)(_ + 1)
// Person(Bob,16)
参见github上的示例。
有很多Lens
的实现。请查看Scala无样版功能镜头和Macrocosm。
虽然谈论FP变异器几乎是自相矛盾的,但Scala作为一种混合面向对象和函数式语言确实有一种用于创建变异器和类似变异器方法的语法:
scala> class C1 { def x: Int = xx; def x_=(i: Int): Unit = xx = i; private var xx: Int = 0 }
defined class C1
scala> val c1 = new C1
c1: C1 = C1@1e818d28
scala> c1.x = 23
c1.x: Int = 23
scala> c1.x
res18: Int = 23
请注意,您不能仅使用变异器。它必须有一个相应的访问器。
补充说明
带有变异器但没有情况类的不可变性
scala> class C2(xInit: Int) { def this = this(0)
def x: Int = xx
def x_=(i: Int): C2 = new C2(i)
private var xx: Int = xInit
}
scala> val c2a = new C2()
c2a: C2 = C2@2f85040b
scala> val c2b = c2a.x = 23
c2b: C2 = C2@74f1bfa9
scala> c2a.x
res19: Int = 0
scala> c2b.x
res20: Int = 23