Alexis King
Alexis King

Reputation: 43842

Apply two Folds or Getters and only succeed when both succeed

Imagine I have the following list:

lst :: [(Bool, Maybe Integer)]
lst = [(True, Just 3), (True, Nothing), (False, Just 12)]

Using the lens library, I want to extract the elements of the tuples, but I only want it to succeed when the second element is Just. I want some optic, split that works like this:

> lst ^.. folded.split (_1.to not) (_2._Just)
[(False, 3), (True, 12)]

I can implement split myself like this:

split :: Getting (First a) s a -> Getting (First b) s b -> Fold s (a, b)
split a b = folding (\x -> (,) <$> (x ^? a) <*> (x ^? b))

…which seems to work. However, this seems like I must be reinventing the wheel. Is there something already provided by the lens library that accomplishes this in an equally nice way?

Upvotes: 6

Views: 105

Answers (1)

danidiaz
danidiaz

Reputation: 27756

The aside combinator takes a Prism that works over the second component of a tuple and returns a Prism that works over the whole tuple:

ghci> lst ^.. folded.aside _Just
[(True,3),(False,12)]

The resulting prism matches when the component is matched, otherwise it fails.

Combining it with to and bimap, we can reproduce your example:

ghci> lst ^.. folded.aside _Just.to (bimap not id)
[(False,3),(True,12)]

To work over the first component, we can use swapped:

ghci> [(Just 3,False)]^..folded.swapped.aside _Just.swapped
[(3,False)]

Upvotes: 6

Related Questions