Search code examples
haskellhaskell-lens

How to get sublist's head using lens?


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)].


Solution

  • 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)))