Каков синтаксис для составления сеттерских линз?

Я новичок в объективе и хочу составить две "установочные" операции, которые будут эквивалентны преобразованию 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 чтобы получить больше эффектов, доступных для сеттеров.

Другие вопросы по тегам