Как использовать библиотеку объективов?

Я снова зашел в тупик, пытаясь работать с библиотекой Edwards lens. Я пытаюсь что-то snoc добавить в конец вектора в контексте состояния:

data Foo = Foo {
  _vec :: Vector Int
}

makeLenses ''Foo

testCons x = vec <>= singleton x

Пока это работает, я хотел бы использовать [cons][2], но я понятия не имею, как это сделать. В документации упоминается [0,1,2] |> 3 === [0,1,2,3], но я понятия не имею, как это сделать в контексте состояния.


person fho    schedule 23.01.2014    source источник
comment
Вы собираетесь добавлять элементы много? Если это так, вам следует использовать последовательность. вместо. получение/отслеживание вектора — это O(n), но O(1) для последовательности; с другой стороны, последовательности имеют произвольный доступ O (log n) по сравнению с O (1) для вектора.   -  person Venge    schedule 24.01.2014
comment
@Kata yay ... Я знаю :-) ... Вероятно, мне следует использовать Foo f a = Foo (f a) в реальном коде.   -  person fho    schedule 24.01.2014


Ответы (2)


Комбинатор (%=) позволяет применить функцию к цели линзы; ты хочешь что-то вроде

stateSnoc :: MonadState Foo m => Int -> m ()
stateSnoc x = vec %= (|> x)
person Venge    schedule 23.01.2014
comment
Хотя это сработает, мне не хватает элегантности других функций lens. - person fho; 24.01.2014
comment
Что вы имеете в виду под «элегантностью»? - person Venge; 24.01.2014
comment
Я ожидал чего-то вроде vec += x. Хотя это, конечно, зарезервировано для Num. - person fho; 24.01.2014
comment
Я думаю, это примерно так же красиво, как вы собираетесь это получить. Нет сеттера, который указывает «позади» последнего элемента, так как, ну, какой в ​​этом смысл? Там никогда не было бы никаких интересных значений. - person Venge; 25.01.2014
comment
Принято, потому что это очевидно правильно. Но я предлагаю прочитать и другой ответ. - person fho; 27.01.2014

snoc кажется простой функцией, определенной для удобства из оригинальной Prism, которая является _Snoc.

Так почему бы не использовать с ним простую функцию MonadState, например modify?

runState (modify $ flip snoc 'a') ['b']
-- ((),"ba")
person danidiaz    schedule 23.01.2014
comment
Мне пришлось бы объединить это с zoom, чтобы сосредоточиться на вложенной записи... Но есть ли способ использовать _Snoc напрямую? Нравится foo . vec . _Snoc .= bar? - person fho; 24.01.2014
comment
Направление призмы _Snoc по умолчанию — от коллекции к паре (collection minus the last element, last element). Но вы можете изменить это с помощью функции review и написать что-то вроде review _Snoc $ (['b'],'a'). Это почти определение snoc, но без каррирования. Однако имейте в виду, что review _Snoc — это не линза, а обычная функция. - person danidiaz; 24.01.2014
comment
Исправление: результат review работает в любом MonadReader. - person danidiaz; 24.01.2014
comment
Хм ... лучше не становится :) ... Я предполагаю, что есть какой-то объектив / сеттер, который указывает «позади» контейнера. - person fho; 24.01.2014
comment
@Florian Я сомневаюсь, что есть Setter, который можно использовать для добавления к контейнерам. Один из (довольно интуитивно понятных) законов, который должен соблюдать Setters, заключается в том, что установка двух раз с двумя разными значениями эквивалентна установке только один раз с последним значением. Но добавление «а», а затем «b» к чему-то не равно добавлению только «b»! Я подозреваю, что добавление и деконструкция по своей сути Prism-подобны. - person danidiaz; 25.01.2014