@Fintan Halpenny I think the problem with a prism is that having a prism assumes there's a single unambiguous case that would be constructed by the injection of the prism

I think we can take two traversals p, q :: Traversal s t a b and obtain a traversal p \/ q :: Traversal s t (a + a) (b + b), but I need to try that out. Assuming that works, view (_A \/ _B) should give us what we want

ok, so I was wrong, it's not b + b, but rather b × b. specifically, we can write this:

(+*) :: Traversal s t a b -> Traversal s' t' a' b' -> Traversal (s × s') (t × t') (a + a') (b × b')
(+*) t1 t2 f (s, s') = liftA2 (,) l r
where
l = t1 (fmap fst . f . Left ) s
r = t2 (fmap snd . f . Right) s'
unit :: Traversal () () Void ()
unit _ _ = pure ()

when there is a full moon and all the types align, this transforms into a monoid:

mappendO :: Semigroup t => Traversal s t a b -> Traversal s t a b -> Traversal s t a b
mappendO t1 t2 = dimapO dup (uncurry (<>)) $ dimapO' dup merge $ t1 +* t2
memptyO :: Monoid t => Traversal s t a b
memptyO = dimapO discard (const mempty) $ dimapO' discard absurd $ unitO

type LOptic f s t a b = (a -> f b) -> s -> f t
lmapO :: (s' -> s) -> LOptic f s t a b -> LOptic f s' t a b
lmapO f o = (. f) . o
rmapO :: Functor f => (t -> t') -> LOptic f s t a b -> LOptic f s t' a b
rmapO f o = (fmap f .) . o
dimapO :: Functor f => (s' -> s) -> (t -> t') -> LOptic f s t a b -> LOptic f s' t' a b
dimapO f g = lmapO f . rmapO g
lmapO' :: Functor f => (b' -> b) -> LOptic f s t a b -> LOptic f s t a b'
lmapO' f o = o . (fmap f .)
rmapO' :: (a -> a') -> LOptic f s t a b -> LOptic f s t a' b
rmapO' f o = o . (. f)
dimapO' :: Functor f => (b' -> b) -> (a -> a') -> LOptic f s t a b -> LOptic f s t a' b'
dimapO' f g = lmapO' f . rmapO' g
dup :: x -> x × x
dup x = (x, x)
merge :: x + x -> x
merge = either id id
discard :: x -> ()
discard = const ()
absurd :: Void -> x
absurd = \case {}

data Thing
= A {x :: SomeType}
| B {x :: SomeType}
| C
_A, _B :: Traversal Thing Thing SomeType SomeType

Ideally we'd just be able to mappend these and get the result as myThing ^? _A <> _B. Unfortunately we don't have a semigroup on the large Thing structure. so we can't discharge the Semigroup t constraint.

Fortunately however, we only want to view, and not make modifications. So we can just throw away the t and get the trivial semigroup (). Here's the overall result:

data Foo = A Int | B Int | C String
_A, _B :: Traversal' Foo Int
_AB :: Traversal Foo () Int Int
_AB = rmapO discard _A `mappendO` rmapO discard _B
whatyouwant :: Foo -> Maybe Int
whatyouwant f = f ^? _AB

@Asad Saeeduddin thanks, I'll check it out! @Fintan Halpenny what/where is it? I guess types would work in this case, but I only want to get values from "one level of structure" and only for fields named x

Can I implement

`f`

easily with some optic usage? (with`generic-lens`

)You should be able to do it with a Prism

@Fintan Halpenny I think the problem with a prism is that having a prism assumes there's a single unambiguous case that would be constructed by the injection of the prism

whereas here we have two cases containing a

`SomeType`

I think we can take two traversals

`p, q :: Traversal s t a b`

and obtain a traversal`p \/ q :: Traversal s t (a + a) (b + b)`

, but I need to try that out. Assuming that works,`view (_A \/ _B)`

should give us what we wantok, so I was wrong, it's not

`b + b`

, but rather`b × b`

. specifically, we can write this:when there is a full moon and all the types align, this transforms into a monoid:

where:

Ah good point, I didn't cop they both had SomeType

Now in your case what we have is:

Ideally we'd just be able to mappend these and get the result as

`myThing ^? _A <> _B`

. Unfortunately we don't have a semigroup on the large`Thing`

structure. so we can't discharge the`Semigroup t`

constraint.Fortunately however, we only want to view, and not make modifications. So we can just throw away the

`t`

and get the trivial semigroup`()`

. Here's the overall result:With generic-lens there's a Traversal which focuses on the type you want

@Asad Saeeduddin thanks, I'll check it out!

@Fintan Halpenny what/where is it? I guess

`types`

would work in this case, but I only want to get values from "one level of structure" and only for fields named`x`