Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 596
Alexis King Avatar asked Jul 26 '17 18:07

Alexis King


1 Answers

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)]
like image 163
danidiaz Avatar answered Nov 05 '22 08:11

danidiaz