Как ни странно, линзы составляются точно так же, как и функции: с (.)
:
setterAB :: Lens' A B
setterBC :: Lens' B C
setterAC = setterAB . setterBC
Однако в вашем примере вы не хотите составлять линзы; вы хотите составить преобразования (которые одновременно являются объективом и фактической операцией), и есть два способа сделать это.
О, и прежде чем мы на самом деле перейдем к этому, давайте немного упростим ваш код, используя (.~)
("set") вместо (%~)
("modify"):
let new_state1 = field1 .~ newVal1 $ state0
let new_state2 = field2 .~ newVal2 $ new_state1
Напрямую, через &
Есть модный оператор &
, который работает очень хорошо. Это просто flip ($)
:
let new_state1 = state0 & field1 .~ newVal1
let new_state2 = new_state & field2 .~ newVal2
Это означает, что теперь вы можете написать:
let new_state =
state0
& field1 .~ newVal1
& field2 .~ newVal2
Монадический
Еще лучше, если у вас действительно где-то есть State
, вы можете полностью избавиться от этого перехода и поместить его в монаду:
let new_state = (flip execState state0) $ do
field1 .= newVal1
field2 .= newVal2
Они определены в терминах MonadState
, поэтому, если вы находитесь в стеке монад, вы можете использовать этот экземпляр напрямую или использовать StateT
, чтобы получить больше эффектов, доступных для сеттеров.
person
Bartek Banachewicz
schedule
20.05.2016