你所询问的问题有一个更为普遍的变体:
(/\)
:: (Functor f)
=> ((a -> (a, a)) -> (c -> (a, c)))
-- ^ Lens' c a
-> ((b -> (b, b)) -> (c -> (b, c)))
-- ^ Lens' c b
-> (((a, b) -> f (a, b)) -> (c -> f c))
-- ^ Lens' c (a, b)
(lens1 /\ lens2) f c0 =
let (a, _) = lens1 (\a_ -> (a_, a_)) c0
(b, _) = lens2 (\b_ -> (b_, b_)) c0
fab = f (a, b)
in fmap (\(a, b) ->
let (_, c1) = lens1 (\a_ -> (a_, a)) c0
(_, c2) = lens2 (\b_ -> (b_, b)) c1
in c2
) fab
infixl 7 /\
只需要关注带有透镜类型同义词签名的类型签名:
Lens' c a -> Lens' c b -> Lens' c (a, b)
它需要两个镜头,并将它们合并成一对字段的镜头。这更为通用,适用于将指向不同类型字段的镜头组合在一起。然而,那么你就必须分别改变这两个字段。
我只是想提供这个解决方案,以防有人正在寻找类似的东西。
(&&&)
。它必须具有类似于(&&&) :: Lens a b -> Lens a b -> Lens a b
的类型,以便您可以像使用组合它的两个镜头一样使用它。鉴于view _1 (1,2) = 1
和view _2 (1,2) = 2
,您期望view (_1 &&& _2) (1,2)
的结果是什么? - Chris Taylor