Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

With the Haskell lens library, how do I treat getters as `first class'?

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?

like image 357
prophet-on-that Avatar asked Oct 16 '14 10:10

prophet-on-that


2 Answers

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}
like image 97
J. Abrahamson Avatar answered Oct 06 '22 17:10

J. Abrahamson


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)
like image 28
Reite Avatar answered Oct 06 '22 17:10

Reite