我正在尝试学习scalaz7镜头。是否有更好的方法来进行集合操作?
case class Outer(left: Inner, right: Inner)
case class Inner(top: Int, bottom: Int)
val left = Lens.lensu[Outer, Inner](
(o,v) => o.copy(left = v),
_.left
)
val right = Lens.lensu[Outer, Inner](
(o,v) => o.copy(right = v),
_.right
)
val top = Lens.lensu[Inner, Int](
(o,v) => o.copy(top = v),
_.top
)
val leftTop = left >=> top
val rightTop = right >=> top
val outer0 = Outer(Inner(10,20), Inner(30, 40))
val outer1 = rightTop.set(leftTop.set(outer0, 11), 33)
更新
我有一种感觉,答案可能是使用状态monad,虽然我几乎不明白为什么这似乎有效。有兴趣知道是否有更简洁的方式。
val modifier = for{
_ <- leftTop := 11
_ <- rightTop := 33
} yield Unit
modifier(outer0)._1 // = Outer(Inner(11,20),Inner(33,40))
答案 0 :(得分:1)
您可以稍微简化State monad版本:
(leftTop := 11) >> (rightTop := 33) exec outer0
或者,如果您愿意:
val modifier = (leftTop := 11) >> (rightTop := 33)
modifier.exec(outer0)
原始状态版本看起来有点奇怪,因为<-
语句中的for
只是调用.flatMap
的语法糖。稍微简化一下,leftTop := 11
的结果类型为State[Outer, Outer, Int]
,大致相当于类型Outer => (Outer, Int)
的函数。 State会跟踪结果的Outer
部分,并将Int
部分传递给.flatMap
。由于您不关心Int
结果,因此您将其分配给_
并忽略它。
>>
执行相同的操作,它是.flatMap
忽略它的参数并且与写作相同:
(leftTop := 11) flatMap (_ => rightTop := 33)
这是一个状态计算,它有一个辅助函数.exec
,它以初始状态(outer0
)运行计算并返回最终状态(丢弃任何结果)。
如果你想避免使用State,你几乎必须按照你开始的方式去做。国家的整个观点是在步骤之间传递中间结果而不明确提及它们。