A simple problem is being solved here, but unfortunately it is a bit involved. The idea is to use the same haskell identifier for a lens and for other purposes. In other words, get the same behavior as:
x = hLens (Label :: Label "x") r ^. x
While still being able to extract the symbol "x" from x, so that things
x .=. 123 could be acceptable. In this case we don't overload
so instead you have to write
x .==. 123.
Elaboration of some ideas from edwardk.
- makeLabelable :: String -> Q [Dec]
- class Labelable l p f s t a b | l s -> a, l t -> b, l s b -> t, l t a -> s where
- (.==.) :: ToSym * Symbol t l => t -> v -> Tagged Symbol l v
- data Labeled l a b = Labeled
- toLabel :: ToSym t t' => t -> Label (t' :: Symbol)
- data Identity a
- class ToSym a b
makeLabelable "x y z" will generate haskell identifiers that work with
are also lenses.
x = hLens' (Label :: Label "x") y = hLens' (Label :: Label "y") z = hLens' (Label :: Label "z")
f s t a b type parameters are the same as those that make
|(Functor f, HasField k x (Record s) a, HasField k x (Record t) b, HFind k x (RecordLabels k t) n, HFind k x (RecordLabels k s) n, HUpdateAtHNat n (Tagged k x b) s, ~ [*] t (HUpdateAtHNatR n (Tagged k x b) s)) => Labelable k x (->) f s t a b|
make a lens
|(~ (* -> *) f Identity, ~ [*] s ( *), ~ [*] t ( *), ~ * a (), ~ * b (), ~ k x' x) => Labelable k x' (Labeled k x) f s t a b|
make a data type that allows recovering the field name
The following code needs to apply the
x for different
f =>, so you would have to write a type signature (rank-2) to allow this
-- with the x defined using hLens' let f x r = let a = r ^. x b = r & x .~ "6" in (a,b)
This alternative won't need a type signature
-- with the x defined as x = Label :: Label "x" let f x r = let a = r ^. hLens x b = r & hLens x .~ "6" in (a,b)
likely unneeded (re)exports
data Identity a
Identity functor and monad.