【问题标题】:Monadic alteration to tuple元组的一元更改
【发布时间】:2015-08-13 02:37:48
【问题描述】:

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

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

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

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

有这样的操作吗?

【问题讨论】:

  • 您是否有理由要使用镜头操作?使用do 表示法很简单:doit (a,b) func = do { c <- func b; return (a,c) }
  • Lenses 出现在我的脑海中,因为我有兴趣从一般意义上解决这个问题——即抽象出形状,在本例中为 2 元组。
  • 也许这个 SO 问题会有所帮助:stackoverflow.com/questions/22209982/…
  • 不知道我是怎么错过的!我将下面的答案标记为正确,因为它是我所问问题的直接解决方案。不过,您的链接肯定比我希望找到的更多,谢谢!
  • Applicative 甚至 Functor 都不是 Monad 的超类,直到 base 4.8 (GHC 7.10)。在去年糟糕的过去,人们不得不使用一种新型包装器将任意 monad 转换为应用程序。

标签: haskell haskell-lens


【解决方案1】:

这绝对是镜头。 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 库以各种方式详细阐述了这个主题。有时它会加强函子约束。有时它将函数推广到一个profunctor。在Equality 的情况下,它删除了函子约束。事实证明,同一个基本类型的形状可以表达很多不同的想法。

【讨论】:

  • 没错。我必须更深入地研究镜头类型。我应该立即注意到 Lens 定义的 Functor 方面。感谢您指出这一点!
  • 不就是:changesecond = flip _2
  • 我建议不要直接调用_2 镜头,而是使用traverseOf:changesecond = flip (traverseOf _2)。而traverseOf = id,它使代码更具可读性。
【解决方案2】:

如果您将Monad 约束放松为Applicative,您的函数就是forM = flip mapMfor = 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。)

【讨论】:

  • 请注意flip traversefor
猜你喜欢
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 2021-11-12
  • 2016-08-08
  • 1970-01-01
  • 1970-01-01
  • 2019-09-17
相关资源
最近更新 更多