I'm new to lens and I want to compose two "setter" operations to be equivalent to this state0 to new_state2 transformation:
let new_state1 = field1 %~ (const newVal1) $ state0
let new_state2 = field2 %~ (const newVal2) $ new_state1
What's the syntax for doing this?
Funny enough, lenses compose just like functions: with a (.)
:
setterAB :: Lens' A B
setterBC :: Lens' B C
setterAC = setterAB . setterBC
In your example, though, you don't want to compose lenses; you want to compose transformations (which is both the lens and the actual operation), and there are two ways to do that.
Oh, and before we actually get to that, let's simplify your code a bit, using (.~)
("set") instead of (%~)
("modify"):
let new_state1 = field1 .~ newVal1 $ state0
let new_state2 = field2 .~ newVal2 $ new_state1
There's a fancy &
operator that works pretty well. It's just flip ($)
:
let new_state1 = state0 & field1 .~ newVal1
let new_state2 = new_state & field2 .~ newVal2
Which means you can now write:
let new_state =
state0
& field1 .~ newVal1
& field2 .~ newVal2
Even better, if you're actually having a State
somewhere, you can get rid of that passing completely and put that in a monad:
let new_state = (flip execState state0) $ do
field1 .= newVal1
field2 .= newVal2
They are defined in terms of MonadState
, so if you're in a monad stack, you can use that instance directly, or use StateT
in order to get more effects available for the setters.