HList- Heterogeneous lists

Safe HaskellNone




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 Source

is Record, Variant. TIP and TIC also have instances, but generally tipyLens' and ticPrism' are more appropriate.
is the label for the field. It tends to have kind Symbol, but others are supported in principle.

Associated Types

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 Lens' (TIP s) a.

tipyLens provides a Lens (TIP s) (TIP t) a b, which tends to need too many type annotations to be practical

(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 ticPrism :: Prism (TIC s) (TIC t) a b, cannot have an instance of Labelable

(HPrism k x s t a b, (~) (* -> * -> *) to (->)) => Labelable k x Variant s t a b

make a Prism (Variant s) (Variant t) a b

LabeledCxt1 * * s t a b => Labelable k x LabeledR s t a b

used with toLabel and/or .==.

HLens k x Record s t a b => Labelable k x Record s t a b

make a Lens (Record s) (Record t) a b

((~) [*] 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 Lens' (RecordU s) 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
>>> r & sameLabels . projected %~ f


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 rs ~ Record s, rt ~ Record t, ra ~ Record a, rb ~ Record b

(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.

The same points apply to the use of hPrism over hLens'.

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

data LabeledTo x a b Source




Show (LabeledTo k x a b) 

data LabeledR x Source




LabeledCxt1 * * s t a b => Labelable k x LabeledR s t a b

used with toLabel and/or .==.

type LabelableTy LabeledR = LabelableLabel 

class ToSym label s | label -> s where Source

Create a Label (x :: Symbol):

toLabel :: LabeledTo x _ _ -> Label x
toLabel :: Label x         -> Label x
toLabel :: Proxy x         -> Label x


toLabel :: label -> Label s Source


ToSym (label x) x 
(~) * (LabeledTo Symbol x (p a (f b)) (p (LabeledR s) (f (LabeledR t)))) (v1 v2 v3) => ToSym (v1 v2 v3) x 

type LabelableTIPCxt x s t a b = (s ~ t, a ~ b, x ~ a, HLens x TIP s t a b) Source

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 = (* -> * -> *) ~ (->)