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
)?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With