1

Considering these types:

data A = A { a :: Int }
data B = B { a :: Int }  -- a again!
data C = C1 A | C2 B

is there a way to get a from C object with some lens (prism?) returning Int and not Maybe Int? Because with pattern-matching (well, or with RecordWildCards):

case c of
  C1 c1 -> a c1
  C2 c2 -> a c2

I can get the Int, but with lens/prisms I think I will always get Maybe Int. Is it possible to be done with lens at all? My intuition is that lens don't know about "determinism" of a accessor over C, that it cannot be Maybe...

RandomB
  • 3,367
  • 19
  • 30
  • 1
    Morally, the combinator you're looking for is [`choosing`](https://hackage.haskell.org/package/lens-5.2.2/docs/Control-Lens-Lens.html#v:choosing), which combines a lens for the `Left` case with a lens for the `Right` one. `choosing` works on `Either` rather than `C`, though, so you'd also have to write an `Iso' C (Either A B)` iso, and at that point [leftaroundabout's solution](https://stackoverflow.com/a/75937076/2751851) is in all likelihood more straightforward in practice. – duplode Apr 06 '23 at 15:50
  • @duplode wow, cool, could you provide some example of `choosing` please? – RandomB Apr 07 '23 at 03:59
  • ah, just found [this](https://stackoverflow.com/questions/37522307/implement-choosing-over-2-lenses-in-haskell) – RandomB Apr 07 '23 at 04:05
  • 1
    found [the example of choosing use](https://stackoverflow.com/questions/52832649/how-can-i-write-a-lens-for-a-sum-type) – RandomB Apr 07 '23 at 04:10
  • 1
    Indeed, leftaroundabout's answer to the second question you've linked above shows what you'd need to do to solve it with `choosing` here. – duplode Apr 07 '23 at 04:38

1 Answers1

6

You can define your own lens

aC :: Lens' C Int
--aC:: Functor f => (Int -> f Int) -> C -> f C
aC f (C1 (A x)) = fmap (C1 . A) $ f x
aC f (C2 (B x)) = fmap (C2 . B) $ f x

Exercise for you: check that this obeys the lens laws.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319