8

I've noticed I'm commonly building functions that get values using lenses, apply some function to the values and return the result. For example, to sum the elements of a pair \pair -> (pair ^. _1) + (pair ^. _2)

I feel like there should be some combinator to combine getters first class and return another getter (maybe of type (b -> c -> d) -> Getter a b -> Getter a c -> Getter a d). Any help?

Bakuriu
  • 98,325
  • 22
  • 197
  • 231

2 Answers2

3

You can always use the Applicative instance for (->)

(+) <$> view _1 <*> view _2 :: Num a => (a,a) -> a

or, a little less generally, you might be aided by the Monoid instance for Getters

>>> view (_1 <> _2) (Sum 1, Sum 2)
Sum {getSum = 3}
J. Abrahamson
  • 72,246
  • 9
  • 135
  • 180
2

As is explained on the top of Control.Lens.Getter, a Getter a b is isomorphic to (a -> b). This means that they contains the same information and can be changed into each other at will. We can turn them into each other by using functions that the lens library provide:

fromGetter :: Getter a b -> (a -> b)
fromGetter g = view g

toGetter :: (a -> b) -> Getter a b
toGetter = to

With this knowledge you can use the Applicative instance for (->), as J. Abrahamson has shown, to create the function you want:

myCombinator :: (b -> c -> d) -> Getter a b -> Getter a c -> Getter a d
myCombinator fn g1 g2 = toGetter (fn <$> fromGetter g1 <*> fromGetter g2)
Reite
  • 1,677
  • 10
  • 12