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 :: k) (r :: [*] -> *) s t a b | x s -> a, x t -> b, x s b -> t, x t a -> s where
- type LabelableTy r :: LabeledOpticType
- type LabeledOptic (x :: k) (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))
- (.==.) :: EnsureLabel x (Label k l) => x -> v -> Tagged k l v
- class Projected r s t a b where
- projected' :: (Projected r t t b b, LabeledOpticF (LabelableTy r) f, LabeledOpticP (LabelableTy r) p) => p (r b) (f (r b)) -> p (r t) (f (r t))
- type LabeledCxt1 s t a b = (s ~ '[], t ~ '[], a ~ (), b ~ ())
- data LabeledTo (x :: k) (a :: *) (b :: *) = LabeledTo
- data LabeledR (x :: [*]) = LabeledR
- class ToSym label (s :: Symbol) | label -> s
- class EnsureLabel x y | x -> y where
- toLabelSym :: EnsureLabel x1 (Label Symbol x2) => x1 -> Label Symbol x2
- data Identity a :: * -> *
- type LabelableTIPCxt x s t a b = (s ~ t, a ~ b, Label x ~ Label a, HLens x TIP s t a b)
- data LabeledOpticType
- type family LabeledOpticF (ty :: LabeledOpticType) :: (* -> *) -> Constraint
- type family LabeledOpticP (ty :: LabeledOpticType) :: (* -> * -> *) -> Constraint
- type family LabeledOpticTo (ty :: LabeledOpticType) (x :: k) :: (* -> * -> *) -> Constraint
Documentation
class SameLength s t => Labelable (x :: k) (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 k x s t a b => Labelable k x TIP s t a b Source # | make a
|
(TICPrism s t a b, (~) * (Label k x) (Label * a), (~) * a b, (~) [*] s t, SameLength * * s t) => Labelable k x TIC s t a b Source # | hLens' :: Label a -> Prism' (TIC s) a note that a more general function Note: `x :: k` according to the instance head, but the instance body forces the kind variable to be * later on. IE. (k ~ *) |
(HPrism k x s t a b, (~) (* -> * -> *) to ((->) LiftedRep LiftedRep)) => Labelable k x Variant s t a b Source # | make a |
HLens k x Record s t a b => Labelable k x Record s t a b Source # | make a |
LabeledCxt1 * * s t a b => Labelable k x LabeledR s t a b Source # | |
((~) [*] 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 Source # | make a |
type LabeledOptic (x :: k) (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
.
(.==.) :: EnsureLabel x (Label k l) => x -> v -> Tagged k 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 Source # | 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 Source # | Prism (Variant s) (Variant t) (Variant a) (Variant b) |
projected' :: (Projected r t t b b, LabeledOpticF (LabelableTy r) f, LabeledOpticP (LabelableTy r) p) => p (r b) (f (r b)) -> p (r t) (f (r t)) 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
class EnsureLabel x y | x -> y where Source #
Convert a type to Label :: Label blah
toLabel :: LabeledTo x _ _ -> Label (x :: Symbol) toLabel (hLens' lx) = (lx :: Label x) toLabel :: Label x -> Label x toLabel :: Proxy x -> Label x
toLabelSym :: EnsureLabel x1 (Label Symbol x2) => x1 -> Label Symbol x2 Source #
fix the k
kind variable to Symbol
Identity functor and monad. (a non-strict monad)
Since: 4.8.0.0
type family LabeledOpticF (ty :: LabeledOpticType) :: (* -> *) -> Constraint Source #
type LabeledOpticF LabelableLens Source # | |
type LabeledOpticF LabelablePrism Source # | |
type LabeledOpticF LabelableLabel Source # | |
type family LabeledOpticP (ty :: LabeledOpticType) :: (* -> * -> *) -> Constraint Source #
type LabeledOpticP LabelableLens Source # | |
type LabeledOpticP LabelablePrism Source # | |
type LabeledOpticP LabelableLabel Source # | |
type family LabeledOpticTo (ty :: LabeledOpticType) (x :: k) :: (* -> * -> *) -> Constraint Source #
type LabeledOpticTo k LabelablePrism x Source # | |
type LabeledOpticTo k LabelableLens x Source # | |
type LabeledOpticTo k LabelableLabel x Source # | |
Orphan instances
((~) (* -> * -> *) to (LabeledTo Symbol x), ToSym * (to p q) x) => HExtend (to p q) (Proxy [*] ((:) * (Lbl n ns desc) xs)) Source # | if the proxy has Data.HList.Label3.Lbl, then everything has to be wrapped in Label to make the kinds match up. |
((~) (* -> * -> *) to (LabeledTo Symbol x), ToSym * (to p q) x) => HExtend (to p q) (Proxy [Symbol] ((:) Symbol x xs)) Source # | |
((~) (* -> * -> *) to (LabeledTo Symbol x), ToSym * (to p q) x) => HExtend (to p q) (Proxy [*] ([] *)) Source # | Together with the instance below, this allows writing
Or with HListPP p = `x .*. `y .*. `z .*. emptyProxy instead of p = Proxy :: Proxy ["x","y","z"] |