Каков синтаксис для составления сеттерских линз?
Я новичок в объективе и хочу составить две "установочные" операции, которые будут эквивалентны преобразованию state0 в new_state2:
let new_state1 = field1 %~ (const newVal1) $ state0
let new_state2 = field2 %~ (const newVal2) $ new_state1
Какой синтаксис для этого?
1 ответ
Достаточно забавно, линзы составляют так же, как функции: с (.)
:
setterAB :: Lens' A B
setterBC :: Lens' B C
setterAC = setterAB . setterBC
Однако в вашем примере вы не хотите создавать линзы; Вы хотите составить преобразования (которые являются объективом и фактической операцией), и есть два способа сделать это.
Да, и прежде чем мы действительно доберемся до этого, давайте немного упростим ваш код, используя (.~)
("набор") вместо (%~)
("Изменить"):
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
чтобы получить больше эффектов, доступных для сеттеров.