objectif ne fait pas un combinateur ready-made pour cela, probablement parce que vous pouvez obtenir des setters illégaux (ou des lentilles) si les foyers des composants se chevauchent.
data Trio a = Trio a a a
deriving (Show)
oneTwo :: Setter' (Trio a) (a, a)
oneTwo = sets $ \f (Trio x y z) -> let (x', y') = f (x, y) in Trio x' y' z
twoThree :: Setter' (Trio a) (a, a)
twoThree = sets $ \f (Trio x y z) -> let (y', z') = f (y, z) in Trio x y' z'
cheating :: Setter' (Trio a) (a, a)
cheating = sets $ \f x -> x & oneTwo %~ f & twoThree %~ f
GHCi> Trio 1 1 1 & cheating %~ bimap (2*) (2*) & cheating %~ bimap (3+) (3+)
Trio 5 10 5
GHCi> Trio 1 1 1 & cheating %~ (bimap (2*) (2*) <&> bimap (3+) (3+))
Trio 5 13 5
Dans votre cas, la plus belle alternative à la construction du compositeur/traversal à la main (comme vous and Cristoph Hegemann faites) semble être liftA2 (>=>) :: ASetter' s a -> ASetter' s a -> ASetter' s a
, comme suggéré par ailleurs par bennofs (grâce Shersh pour le lien). Si vous arrive d'avoir une lentille à une paire homogène (ou un autre Bitraversable
) qui traînent, vous pouvez obtenir le traversal sortir avec both
:
data Foo = Foo
{ _bar, _baz :: Int
} deriving (Show)
makeLenses ''Foo
barBaz :: Iso' Foo (Int, Int)
barBaz = iso ((,) <$> view bar <*> view baz) (Foo <$> fst <*> snd)
GHCi> Foo 1 2 & barBaz . both %~ (2*)
Foo {_bar = 2, _baz = 4}
Une autre possibilité est d'exploiter Data.Data.Lens
à obtenir un traversal de tous les champs d'un certain type:
{-# LANGUAGE DeriveDataTypeable #-}
import Control.Lens
import Data.Data.Lens
import Data.Data
data Foo = Foo
{ _bar, _baz :: Int
} deriving (Show, Data, Typeable)
makeLenses ''Foo
barBaz :: Traversal' Foo Int
barBaz = template
GHCi> Foo 1 2 & barBaz %~ (2*)
Foo {_bar = 2, _baz = 4}
Cela semble répondre à votre question: http://stackoverflow.com/questions/17528119/combined-lenses – Shersh
Si vous utilisiez un tuple au lieu de 'Foo', vous pourriez faire quelque chose comme [' (1,2) et les deux. ~ 10'] (https://hackage.haskell.org/package/lens-4.15.1/docs/Control-Lens-Traversal.html#v:both) pour mettre les deux éléments du tuple à '10'. – Alec