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

Я новичок в объективе и хочу составить две операции "установщика", которые будут эквивалентны этому преобразованию state0 в new_state2:

  let new_state1 = field1 %~ (const newVal1) $ state0
  let new_state2 = field2 %~ (const newVal2) $ new_state1

Какой синтаксис для этого?


person daj    schedule 20.05.2016    source источник
comment
Я также настоятельно рекомендую прочитать этот текст.   -  person Bartek Banachewicz    schedule 21.05.2016


Ответы (1)


Как ни странно, линзы составляются точно так же, как и функции: с (.):

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