Монадическое изменение кортежа
Я ищу функцию с типом, похожим на:
Monad m => (a, b) -> (b -> m c) -> m (a, c)
Мне кажется это какая-то комбинация связывания (>>=
) и операция линзы.
Я знаю, что я могу решить эту проблему с помощью сопоставления с образцом после привязки, но моя интуиция говорит мне, что есть "более простой" способ написать это, используя линзы.
Есть ли такая операция?
2 ответа
Это определенно линзы. Монада на самом деле немного отвлекает, потому что все, что вам нужно, это функтор:
changesecond (a, b) f = fmap (a,) (f b)
Я уверен, что _2
Объектив может быть сделан, чтобы делать ваши ставки с помощью основной вещи объектива, как, возможно, over
но я еще не слишком знаком с библиотекой.
редактировать
Комбинатор действительно не нужен. Ты можешь написать
changesecond pair f = _2 f pair
Вы должны быть в состоянии понять это из общего определения Lens
тип.
Редактировать 2
Этот простой пример демонстрирует основную тему изготовления линз Ван Лаарховена:
- Извлечь фокус из контекста.
- Примените данную функцию, чтобы получить множество результатов.
- использование
fmap
восстановить контекст к результатам.
Эд Кметт lens
Библиотека развивает эту тему по-разному. Иногда это усиливает ограничение функтора. Иногда это обобщает функцию до профессора. В случае Equality
, он удаляет ограничение функтора. Просто получается, что одна и та же форма базового типа может выражать множество разных идей.
Ваша функция просто forM = flip mapM
, или же for = flip traverse
если вы расслабитесь Monad
ограничение к Applicative
, Functor
быть пройденным (,) a
,
Prelude> let foo :: Applicative f => (a, b) -> (b -> f c) -> f (a, c); foo p k = traverse k p
Prelude> :t foo
foo :: Applicative f => (a, b) -> (b -> f c) -> f (a, c)
Prelude> foo (1,2) (\x -> [x,2*x])
[(1,2),(1,4)]
(Кроме того, как указывает dfeuer, вам даже не нужно Applicative
в этом конкретном случае.)