使用 Lens 更改数据 class 的多个属性
Changing multiple attributes of a data class with a Lens
我正在 Kotlin 中试验 Lenses,我想知道是否有一种优雅的方法可以同时更改一个对象的多个属性。假设我的域看起来像这样:
@optics
data class Parameters(
val duration: Int,
val length: Int) {
companion object
}
@optics
data class Calculation(
val product: String
val parameters: Parameters) {
companion object
}
感谢 @optics
注释,编辑单个字段很容易:
val calculation = Calculation(product = "prod", Parameters(duration = 10, length = 15))
Calculation.product.modify(calculation) { selectedProduct }
Calculation.parameters.duration(calculation) { newDuration() }
Calculation.parameters.length(calculation) { 10 }
这些镜头单独使用时效果很好,但是当我想同时应用三种变换时,正确的模式是什么?我可以使用 var
并每次都覆盖 calculation
,但这对我来说不是很习惯。
Arrow 目前不公开此类功能,但您可以轻松地自己编写通用解决方案。
下面的代码片段演示了它是如何实现的,您可以添加额外的方法来组合从 Lens<S, Tuple2<FA, FB>>
到 Lens<S, Tuple3<FA, FB, FC>>
等
@optics data class Char(val name: String, val health: Int) {
companion object
}
infix fun <S, FA, FB> Lens<S, FA>.aside(other: Lens<S, FB>): Lens<S, Tuple2<FA, FB>> = object : Lens<S, Tuple2<FA, FB>> {
override fun get(s: S): Tuple2<FA, FB> = Tuple2(this@aside.get(s), other.get(s))
override fun set(s: S, b: Tuple2<FA, FB>): S = other.set(this@aside.set(s, b.a), b.b)
}
fun main() {
val original = Char("", 0)
val charName: Lens<Char, String> = Char.name
val charHealth: Lens<Char, Int> = Char.health
val charNameAndHealth: Lens<Char, Tuple2<String, Int>> = charName.aside(charHealth)
charNameAndHealth.modify(original) { Tuple2("Test", 30) }
}
我正在 Kotlin 中试验 Lenses,我想知道是否有一种优雅的方法可以同时更改一个对象的多个属性。假设我的域看起来像这样:
@optics
data class Parameters(
val duration: Int,
val length: Int) {
companion object
}
@optics
data class Calculation(
val product: String
val parameters: Parameters) {
companion object
}
感谢 @optics
注释,编辑单个字段很容易:
val calculation = Calculation(product = "prod", Parameters(duration = 10, length = 15))
Calculation.product.modify(calculation) { selectedProduct }
Calculation.parameters.duration(calculation) { newDuration() }
Calculation.parameters.length(calculation) { 10 }
这些镜头单独使用时效果很好,但是当我想同时应用三种变换时,正确的模式是什么?我可以使用 var
并每次都覆盖 calculation
,但这对我来说不是很习惯。
Arrow 目前不公开此类功能,但您可以轻松地自己编写通用解决方案。
下面的代码片段演示了它是如何实现的,您可以添加额外的方法来组合从 Lens<S, Tuple2<FA, FB>>
到 Lens<S, Tuple3<FA, FB, FC>>
等
@optics data class Char(val name: String, val health: Int) {
companion object
}
infix fun <S, FA, FB> Lens<S, FA>.aside(other: Lens<S, FB>): Lens<S, Tuple2<FA, FB>> = object : Lens<S, Tuple2<FA, FB>> {
override fun get(s: S): Tuple2<FA, FB> = Tuple2(this@aside.get(s), other.get(s))
override fun set(s: S, b: Tuple2<FA, FB>): S = other.set(this@aside.set(s, b.a), b.b)
}
fun main() {
val original = Char("", 0)
val charName: Lens<Char, String> = Char.name
val charHealth: Lens<Char, Int> = Char.health
val charNameAndHealth: Lens<Char, Tuple2<String, Int>> = charName.aside(charHealth)
charNameAndHealth.modify(original) { Tuple2("Test", 30) }
}