I'm trying to learn scalaz7 lenses. Is there a better way to chain set operations?
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)
Update:
I have a feeling that the answer might be to use the state monad, though I barely understand why this seems to work. Would be interested to know if there is a neater way.
val modifier = for{
_ <- leftTop := 11
_ <- rightTop := 33
} yield Unit
modifier(outer0)._1 // = Outer(Inner(11,20),Inner(33,40))
You can simplify the State monad version somewhat:
Or, if you prefer:
Your original State version looks a little weird since the
<-in aforstatement is just syntax sugar for calls to.flatMap. Simplifying things a bit, the result ofleftTop := 11has a type likeState[Outer, Outer, Int], which is roughly equivalent to a function with typeOuter => (Outer, Int). State keeps track of theOuterpart of the result and passes theIntpart to.flatMap. Since you don't care about theIntresult, you assign it to_and ignore it.The
>>does the same thing, it's a.flatMapthat ignores it's argument and is the same as writing:The result of this is a State computation, which has a helper function
.execthat runs the computation with an initial state (outer0) and returns the final state (discarding any result).If you want to avoid using State, you'll pretty much have to do it the way you started out. The whole point of State is to pass intermediate results between steps without explicitly mentioning them.