Nik*_*kov 15 haskell lenses haskell-lens
使用镜头库我可以将修改功能应用于各个目标,如下所示:
Prelude Control.Lens> (1, 'a', 2) & _1 %~ (*3)
(3,'a',2)
Prelude Control.Lens> (1, 'a', 2) & _3 %~ (*3)
(1,'a',6)
Run Code Online (Sandbox Code Playgroud)
如何组合这些单独的镜头(_1和_3),以便能够同时对两个目标执行此更新?我期待以下精神:
Prelude Control.Lens> (1, 'a', 2) & ??? %~ (*3)
(3,'a',6)
Run Code Online (Sandbox Code Playgroud)
ben*_*ofs 19
利用untainted来自Settable于类型的类Control.Lens.Internal.Setter,它可以在两个setter方法结合起来,但结果也只会是一个二传手,而不是一个getter.
import Control.Lens.Internal.Setter
-- (&&&) is already taken by Control.Arrow
(~&~) :: (Settable f) => (c -> d -> f a) -> (c -> a -> t) -> c -> d -> t
(~&~) a b f = b f . untainted . a f
Run Code Online (Sandbox Code Playgroud)
你可以测试一下:
>>> import Control.Lens
>>> (1, 'a', 2) & (_1 ~&~ _3) %~ (*3)
(3,'a',6)
Run Code Online (Sandbox Code Playgroud)
编辑
您实际上不需要使用内部函数.您可以使用Mutator是monad的事实:
{-# LANGUAGE NoMonomorphismRestriction #-}
import Control.Monad
import Control.Applicative
(~&~) = liftA2 (>=>)
-- This works too, and is maybe easier to understand:
(~&~) a b f x = a f x >>= b f
Run Code Online (Sandbox Code Playgroud)
您要求的内容有所不同,哪种更为通用:
(/\)
:: (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 /\
Run Code Online (Sandbox Code Playgroud)
只关注具有镜头类型同义词的类型签名:
Lens' c a -> Lens' c b -> Lens' c (a, b)
Run Code Online (Sandbox Code Playgroud)
它需要两个镜头,并将它们组合成一对镜头到一对镜头.这稍微更为通用,适用于组合指向不同类型字段的镜头.但是,你必须分别改变这两个字段.
我只是想把这个解决方案扔出去,以防人们在寻找这样的东西.
| 归档时间: |
|
| 查看次数: |
1689 次 |
| 最近记录: |