我正在寻找类似于以下类型的函数:
Monad m => (a, b) -> (b -> m c) -> m (a, c)
在我看来,它是绑定(>>=
)和镜头操作的一些组合。
我知道我可以在绑定后使用模式匹配来解决这个问题,但我的直觉告诉我,通过利用镜头来编写这个“更简单”的方法。
有没有这样的操作?
答案 0 :(得分:8)
这绝对是镜头。 monad实际上只是一点点分心,因为你需要的只是一个仿函数:
changesecond (a, b) f = fmap (a,) (f b)
我非常确定_2
镜头可以用over
之类的基本镜头进行竞价,但我还不熟悉这个库。
确实不需要组合器。你可以写
changesecond pair f = _2 f pair
您应该能够从Lens
类型的一般定义中解决这个问题。
这个简单的例子展示了Van Laarhoven镜片结构的主题:
fmap
将上下文恢复为结果。 Ed Kmett的lens
图书馆以各种方式详细阐述了这一主题。有时它会加强仿函数约束。有时它会将函数概括为profunctor。在Equality
的情况下,它会删除仿函数约束。事实证明,相同的基本类型形状可以表达许多不同的想法。
答案 1 :(得分:6)
如果您将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
。)