5

I have a value:

my :: [(A, Either B [C])]

and I want to get [(A, C)] from it using lens. The result items are items from my that:

  1. the second item in tuples is Right [C]
  2. the list in this Right [C] has at least 1 item, so the result get the first (head) item from it

I know how to get the [C] but I don't know how to get [(A, C)].

RandomB
  • 3,367
  • 19
  • 30

1 Answers1

6

You want:

my ^.. each . runFold (second (Fold (_Right . _head)))

The idea is that _Right . _head is a fold that selects a C from an Either B [C]. You can make it select an (A, C) from an (A, Either B [C]), using second from Control.Arrow. However, to do this, you need to reify the fold (i.e., turn it into a newtype with an Arrow instance) using Fold and then unreify it with runFold. The resulting fold specializes to:

runFold (second (Fold (_Right . _head))) :: Fold (A, Either B [C]) (A,C)

which selects either zero or one instances of (A,C), and you can compose it with each to fold over a traversable container, like a list:

runFold (second (Fold (_Right . _head))) :: Fold [(A, Either B [C])] (A,C)

to select all of the (A,C) from the container's elements.

Sample code:

import Control.Lens
import Control.Arrow

my :: [(Int, Either Double [Char])]
my = [(1, Right "apple"), (2, Left 1.5), (3, Right "bear"), (4, Right "")]

main = do
  print $ my ^.. each . runFold (second (Fold (_Right . _head)))
K. A. Buhr
  • 45,621
  • 3
  • 45
  • 71