Как я могу использовать `over` из Control.Lens, но выполнять монадическое действие и собирать результаты?

Проблема довольно проста. У меня есть структура, которая выглядит примерно так

data Foo = Foo [Bar]
data Bar = Boo | Moo Item Int
data Item = Item String Int

и у меня есть линза для изменения содержимого Items внутри структуры данных, например эта

let foos = [Foo [Boo, Moo (Item "bar" 20) 10]]
over (traverse._Foo._Moo._1._Item._1) ("foo" ++) foos

-- which yields [Foo [Boo, Moo (Item "foobar" 20) 10]]

Структура здесь не важна, я просто хотел показать пример, в котором используются призмы и что-то глубоко вложенное.

Теперь проблема в том, что мне нужно, чтобы функция, переданная over, была String -> IO String, а не просто String -> String. Похожая вещь на то, что я ищу здесь, что-то вроде mapM, но с линзами. Можно ли сделать что-то подобное?


person Jakub Arnold    schedule 01.07.2014    source источник


Ответы (1)


Lens предоставляет функцию traverseOf, точно такую ​​же, как mapM, но берет линзоподобный (он требует обхода, который включает в себя линзы и примы), над которым вы хотите map.

traverseOf :: Functor f => Iso s t a b       -> (a -> f b) -> s -> f t
traverseOf :: Functor f => Lens s t a b      -> (a -> f b) -> s -> f t
traverseOf :: Applicative f => Traversal s t a b -> (a -> f b) -> s -> f t

Итак, для вашего примера вы можете просто использовать:

traverseOf (traverse._Foo._Moo._1._Item._1) (... expression of type String -> IO String ...) foos

Существует также операторная версия traverseOf, называемая %%~.


Если вы немного знакомы с представлением линз в библиотеке линз, вы могли заметить, что traverseOf = id! Итак, с этими знаниями вы можете просто переписать пример:

(traverse._Foo._Moo._1._Item._1) (... expression of type String -> IO String ...) foos

(Вы даже использовали traverse, который всего лишь mapM для построения обхода! Линзы/примы такие же, как traverse, но более конкретные.)

Но это только в сторону, тем не менее, вы можете использовать traverseOf для ясности.

person bennofs    schedule 01.07.2014