Монадическое изменение кортежа

Я ищу функцию с типом, похожим на:

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

Этот простой пример демонстрирует основную тему изготовления линз Ван Лаарховена:

  1. Извлечь фокус из контекста.
  2. Примените данную функцию, чтобы получить множество результатов.
  3. использование 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 в этом конкретном случае.)

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