Safe Haskell | None |
---|---|
Language | Haskell2010 |
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
like 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.
- class SameLength s t => Labelable x r s t a b | x s -> a, x t -> b, x s b -> t, x t a -> s where
- type LabelableTy r :: LabeledOpticType
- hLens' :: Label x -> LabeledOptic x r s t a b
- type LabeledOptic x r s t a b = forall ty to p f. (ty ~ LabelableTy r, LabeledOpticF ty f, LabeledOpticP ty p, LabeledOpticTo ty x to) => (a `p` f b) `to` (r s `p` f (r t))
- (.==.) :: ToSym label l => label -> v -> Tagged Symbol l v
- class Projected r s t a b where
- projected :: (ty ~ LabelableTy r, LabeledOpticP ty p, LabeledOpticF ty f) => (r a `p` f (r b)) -> r s `p` f (r t)
- projected' :: (LabeledOpticP (LabelableTy r) p, LabeledOpticF (LabelableTy r) f, Projected r s s b b) => p (r b) (f (r b)) -> p (r s) (f (r s))
- type LabeledCxt1 s t a b = (s ~ [], t ~ [], a ~ (), b ~ ())
- data LabeledTo x a b = LabeledTo
- data LabeledR x = LabeledR
- class ToSym label s | label -> s where
- data Identity a :: * -> *
- type LabelableTIPCxt x s t a b = (s ~ t, a ~ b, x ~ a, HLens x TIP s t a b)
- data LabeledOpticType
- type family LabeledOpticF ty :: (* -> *) -> Constraint
- type family LabeledOpticP ty :: (* -> * -> *) -> Constraint
- type family LabeledOpticTo ty x :: (* -> * -> *) -> Constraint
Documentation
class SameLength s t => Labelable x r s t a b | x s -> a, x t -> b, x s b -> t, x t a -> s where Source
type LabelableTy r :: LabeledOpticType Source
hLens' :: Label x -> LabeledOptic x r s t a b Source
LabelableTIPCxt x s t a b => Labelable * x TIP s t a b | make a
|
(TICPrism s t a b, (~) * x a, (~) * a b, (~) [*] s t, SameLength * * s t) => Labelable * x TIC s t a b | hLens' :: Label a -> Prism' (TIC s) a note that a more general function |
(HPrism k x s t a b, (~) (* -> * -> *) to (->)) => Labelable k x Variant s t a b | make a |
LabeledCxt1 * * s t a b => Labelable k x LabeledR s t a b | |
HLens k x Record s t a b => Labelable k x Record s t a b | make a |
((~) [*] s t, (~) * a b, IArray UArray a, (~) * a (GetElemTy s), HLensCxt k x RecordU s t a b) => Labelable k x RecordU s t a b | make a |
type LabeledOptic x r s t a b = forall ty to p f. (ty ~ LabelableTy r, LabeledOpticF ty f, LabeledOpticP ty p, LabeledOpticTo ty x to) => (a `p` f b) `to` (r s `p` f (r t)) Source
This alias is the same as Control.Lens.Optic, except the (->) in Optic
is a type parameter to
in LabeledOptic.
Depending on the collection type (see instances of LabelableTy
),
the type variables to, p, f
are constrained such that the resulting
type is a Lens (r s) (r t) a b
, Prism (r s) (r t) a b
or a
LabeledTo x _ _
. The latter can be used to recover the label (x
) when
used as an argument to .==.
or equivalently toLabel
.
(.==.) :: ToSym label l => label -> v -> Tagged Symbol l v infixr 4 Source
modification of .=.
which works with the labels from this module,
and those from Data.HList.Label6. Note that this is not strictly a
generalization of .=.
, since it does not work with labels like
Data.HList.Label3 which have the wrong kind.
multiple lookups
class Projected r s t a b where Source
Sometimes it may be more convenient to operate on a record/variant
that only contains the fields of interest. projected
can then be used
to apply that function to a record that contains additional elements.
>>>
:set -XViewPatterns
>>>
import Data.HList.RecordPuns
>>>
let f [pun| (x y) |] = case x+y of z -> [pun| z |]
>>>
:t f
f :: Num v => Record '[Tagged "x" v, Tagged "y" v] -> Record '[Tagged "z" v]
>>>
let r = (let x = 1; y = 2; z = () in [pun| x y z |])
>>>
r
Record{x=1,y=2,z=()}
>>>
r & sameLabels . projected %~ f
Record{x=1,y=2,z=3}
projected :: (ty ~ LabelableTy r, LabeledOpticP ty p, LabeledOpticF ty f) => (r a `p` f (r b)) -> r s `p` f (r t) Source
(H2ProjectByLabels (LabelsOf a) s a_ _s_minus_a, HRLabelSet a_, HRLabelSet a, HRearrange (LabelsOf a) a_ a, HLeftUnion b s bs, HRLabelSet bs, HRearrange (LabelsOf t) bs t, HRLabelSet t) => Projected Record s t a b | Lens rs rt ra rb where |
(ExtendsVariant b t, ProjectVariant s a, ProjectExtendVariant s t, HLeftUnion b s bs, HRLabelSet bs, HRearrange (LabelsOf t) bs t) => Projected Variant s t a b | Prism (Variant s) (Variant t) (Variant a) (Variant b) |
projected' :: (LabeledOpticP (LabelableTy r) p, LabeledOpticF (LabelableTy r) f, Projected r s s b b) => p (r b) (f (r b)) -> p (r s) (f (r s)) Source
Lens' (Record s) (Record a)
Prism' (Variant s) (Variant a)
comparison with hLens
Note that passing around variables defined with hLens'
doesn't get
you exactly the same thing as calling hLens
at the call-site:
The following code needs to apply the x
for different Functor
f =>
, so you would have to write a type signature (rank-2) to allow this
definition:
-- 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)
It may work to use hLens'
instead of hLens
in the second code,
but that is a bit beside the point being made here.
likely unneeded (re)exports
type LabeledCxt1 s t a b = (s ~ [], t ~ [], a ~ (), b ~ ()) Source
sets all type variables to dummy values: only the Labeled x
part is actually needed
LabeledCxt1 * * s t a b => Labelable k x LabeledR s t a b | |
type LabelableTy LabeledR = LabelableLabel |
class ToSym label s | label -> s where Source
toLabel :: LabeledTo x _ _ -> Label x toLabel :: Label x -> Label x toLabel :: Proxy x -> Label x
data Identity a :: * -> *
Identity functor and monad.
type LabelableTIPCxt x s t a b = (s ~ t, a ~ b, x ~ a, HLens x TIP s t a b) Source
type family LabeledOpticF ty :: (* -> *) -> Constraint Source
type LabeledOpticF LabelableLabel = (* -> *) ~ Identity | |
type LabeledOpticF LabelablePrism = Applicative | |
type LabeledOpticF LabelableLens = Functor |
type family LabeledOpticP ty :: (* -> * -> *) -> Constraint Source
type LabeledOpticP LabelableLabel = (* -> * -> *) ~ (->) | |
type LabeledOpticP LabelablePrism = Choice | |
type LabeledOpticP LabelableLens = (* -> * -> *) ~ (->) |
type family LabeledOpticTo ty x :: (* -> * -> *) -> Constraint Source
type LabeledOpticTo k LabelableLabel x = (* -> * -> *) ~ LabeledTo k x | |
type LabeledOpticTo k LabelablePrism x = (* -> * -> *) ~ (->) | |
type LabeledOpticTo k LabelableLens x = (* -> * -> *) ~ (->) |