对元组的单子改变

Monadic alteration to tuple

我正在寻找类似于以下类型的函数:

Monad m => (a, b) -> (b -> m c) -> m (a, c)

在我看来,它是绑定 (>>=) 和镜头操作的某种组合。

我知道我可以在绑定后使用模式匹配来解决这个问题,但我的直觉告诉我有一种 "simpler" 方法可以通过利用镜头来编写它。

有没有这样的操作?

如果您将 Monad 限制放宽到 Applicative,您的函数就是 forM = flip mapM,或者 for = flip traverse。遍历的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。)

这绝对是 lensy。 monad 实际上只是有点让人分心,因为你只需要一个函子:

changesecond (a, b) f = fmap (a,) (f b)

我很确定 _2 镜头可以用像 over 这样的基本镜头来满足你的要求,但我对图书馆还不太熟悉。

编辑

真的不需要组合器。你可以写

changesecond pair f = _2 f pair

您应该能够从 Lens 类型的一般定义中解决这个问题。

编辑 2

这个简单的例子展示了 Van Laarhoven 镜头构造的主题:

  1. 从上下文中提取焦点。
  2. 应用给定的函数产生一个函数式的结果。
  3. 使用 fmap 将上下文恢复为结果。

Ed Kmett 的 lens 图书馆以各种方式阐述了这个主题。有时它会加强函子约束。有时它会将功能概括为发音器。在 Equality 的情况下,它删除了函子约束。原来同一个基本型的形状可以表达出很多不同的想法。