Lenses with interdependent (simultaneous) updates

Let's say I have:

{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TupleSections #-} import Control.Lens data T ab = T { _foo :: a , _bar :: a -> b } makeLenses ''T 

a appears in both foo and bar , so updates should be "simulated." This is possible without lenses:

 eg1 :: T a (b -> c) -> b -> T (a, b) c eg1 (T foo bar) b = T (foo, b) (uncurry bar) 

But how can I do this with lenses? The following does not work with availability checking:

 eg :: T a (b -> c) -> b -> T (a, b) c eg tb = t & foo %~ (, b) & bar %~ uncurry 
+7
haskell lens
source share
1 answer

You cannot do this using automatically created lenses for T If you want to stretch a little, you can first define

 data T' abc = T' { _foo' :: c, _bar' :: a -> b} tt :: Iso (T ab) (T a' b') (T' aba) (T' a' b' a') tt = dimap (\(T xg) -> T' xg) (fmap (\(T' xg) -> T xg)) 

Then you can (automatically) create type-changing lenses for T' and use tt to use them to change values โ€‹โ€‹of type T ab through an isomorphism.

For example, by slightly changing the arguments, you can write

 eg :: b -> T a (b -> c) -> T (a, b) c eg b = over tt $ (foo' %~ (,b)) . (bar' %~ uncurry) 

Another approach, which would probably be better if you don't need to fuss with T , is too much to define as newtype around T' :

 newtype T ab = T { getT :: T' aba } 

Then you can skip Iso and just put things together. Reordering the arguments in the same way

 eg' :: b -> T a (b -> c) -> T (a, b) c eg' b = T . (foo' %~ (,b)) . (bar' %~ uncurry) . getT 
+6
source share

All Articles