3

我正在尝试学习 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)

更新:

我有一种感觉,答案可能是使用 state monad,尽管我几乎不明白为什么这似乎有效。有兴趣知道是否有更整洁的方法。

val modifier = for{
    _ <- leftTop := 11
    _ <- rightTop := 33
} yield Unit

modifier(outer0)._1   // = Outer(Inner(11,20),Inner(33,40))
4

1 回答 1

1

您可以稍微简化 State monad 版本:

(leftTop := 11) >> (rightTop := 33) exec outer0

或者,如果您愿意:

val modifier = (leftTop := 11) >> (rightTop := 33)
modifier.exec(outer0)

你原来的 State 版本看起来有点奇怪,因为<-infor语句只是调用.flatMap. 稍微简化一下, 的结果leftTop := 11有一个 like 类型State[Outer, Outer, Int],大致相当于一个带有 type 的函数Outer => (Outer, Int)。State 跟踪Outer结果的一部分并将该Int部分传递给.flatMap. 由于您不关心Int结果,因此您将其分配给_并忽略它。

The>>做同样的事情,它.flatMap忽略了它的论点并且与写作相同:

(leftTop := 11) flatMap (_ => rightTop := 33)

其结果是状态计算,它有一个辅助函数.exec,该函数使用初始状态 ( outer0) 运行计算并返回最终状态(丢弃任何结果)。

如果你想避免使用 State,你几乎必须按照你开始的方式去做。State 的全部意义在于在步骤之间传递中间结果而不明确提及它们。

于 2014-01-17T11:56:43.103 回答