Question

I have a total map from type A to type B.

import qualified Data.Map as M
import Data.Maybe

tmGet k m = fromJust $ M.lookup k m

tmSet k v = M.insert k v

I used Data.Map as an example implementation but it can be anything, e.g. an Array or even a Bool-indexed tuple:

tmGet True  = fst
tmGet False = snd

I want to have a tmAt function to construct a lens:

(42, 665) ^. tmAt True == 42
(42, 665) & tmAt False +~ 1 == (42, 666)

The question is how do I construct tmAt out of tmGet and tmSet (or tmModify)?

Was it helpful?

Solution

If you look at the documentation for the Control.Lens module there's a very handy image of different parts of the lens package. Since you want to construct a Lens, you can look at the Lens part of the diagram. The topmost function shown is

lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b

This constructs a Lens from a getter and a setter.

The function s -> a is a getter – the type signature means, "If you give me a data structure s, I will pick an a value out of it." The s -> b -> t function is the setter, and the type signature means, "If you give me an s and a new value b, I will create for you a new structure t." (The types are different because lenses can actually change types of things.)

If your getter is tmGet and your setter is tmSet, you can therefore construct a lens with

tmAt :: Boolean -> Lens s t a b
tmAt b = lens (tmGet b) (tmSet b)

for whatever your actual s, t, a, and b parameters are. In the example of a tuple, it would be

tmAt :: Bool -> Lens (a, a) (a, a) a a

(In other words, if you give the Lens a function a -> a, it can transform an (a, a)-tuple into another (a, a)-tuple.)


If you want to be fancy, you can also rewrite tmAt as

tmAt = lens <$> tmGet <*> tmSet

OTHER TIPS

Once you have defined tmGet and tmSet to be of type

tmGet :: k -> f v -> v
tmSet :: k -> f v -> v -> f v

you can defined a family of lenses by feeding the lens constructor lens with your parameterized getters and setters. Here's how you would do it for a pair indexed by a Bool

tmGet True  = fst
tmGet False = snd

tmSet True  (_,b) a = (a,b)
tmSet False (a,_) b = (a,b)

tmAt b = lens (tmGet b) (tmSet b)

Now in GHCI

>>> (42,665) ^. tmAt True
42
>>> (42,665) & tmAt False +~ 1
(42,666)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top