Copyright | (C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke |
---|---|
Safe Haskell | None |
Language | Haskell2010 |
The HList library
This module re-exports everything needed to use HList.
- module Data.HList.FakePrelude
- module Data.HList.HListPrelude
- module Data.HList.HArray
- module Data.HList.HOccurs
- module Data.HList.HTypeIndexed
- module Data.HList.Record
- module Data.HList.RecordPuns
- data RecordU l
- data RecordUS x
- class SortForRecordUS x x' | x -> x' where
- sortForRecordUS :: Record x -> Record x'
- class HUpdateMany lv rx where
- hUpdateMany :: Record lv -> rx -> rx
- hMapRU :: HMapCxt RecordU f x y => f -> RecordU x -> RecordU y
- class HFindMany ls r ns | ls r -> ns
- class HNats2Integrals ns where
- hNats2Integrals :: Integral i => Proxy ns -> [i]
- class RecordUSCxt x u | x -> u, u -> x
- class HLookupByHNatUS n us e | n us -> e
- class HLookupByHNatUS1 r n u us e | r n u us -> e
- type family HSubtract n1 n2 :: Either HNat HNat
- class HMapUnboxF xs us | xs -> us, us -> xs
- data UnboxF
- data BoxF
- data EqTagValue
- type family GetElemTy x :: *
- class ElemTyEq xs
- class RecordToRecordU x
- class RecordUToRecord x
- module Data.HList.HList
- module Data.HList.HZip
- hSort :: HSort x y => HList x -> HList y
- type HSort x y = HSortBy HLeFn x y
- class (SameLength a b, HEqByFn le) => HSortBy le a b | le a -> b where
- data HLeFn
- data HDown a
- class HSetBy (HNeq HLeFn) ps => HSet ps
- class HEqByFn lt => HSetBy lt ps
- class HIsSet ps b | ps -> b
- class HEqByFn lt => HIsSetBy lt ps b | lt ps -> b
- class HEqByFn le => HAscList le ps
- class HEqByFn le => HIsAscList le xs b | le xs -> b
- class HLengthEq xs n => HCurry' n f xs r | f xs -> r, r xs -> f, n f -> xs, xs -> n where
- hCurry :: (HCurry' n f xs r, ArityFwd f n, ArityRev f n) => (HList xs -> r) -> f
- hUncurry :: (HCurry' n f xs r, ArityFwd f n, ArityRev f n) => f -> HList xs -> r
- hCompose :: (HCurry' n2 f2 xs1 r, HCurry' n1 f1 xs x, HCurry' n f xsys r, HSplitAt1 ([] *) n1 xsys xs xs1, HAppendList1 * xs xs1 xsys, ArityFwd f2 n2, ArityFwd f1 n1, ArityRev f2 n2, ArityRev f1 n1) => (x -> f2) -> f1 -> f
- data TIP l
- emptyTIP :: TIP []
- tipyUpdate :: (HUpdateAtLabel * record v v r r, SameLength' * * r r) => v -> record r -> record r
- tipyLens :: (HAllTaggedEq t, HAllTaggedEq s, HLabelSet [*] (LabelsOf t), HLabelSet [*] (LabelsOf s), HasField * b (Record t) b, HasField * b (Record s) b, HUpdateAtLabel2 * b b t s, HUpdateAtLabel2 * b b s t, SameLength' * * t s, SameLength' * * s t, SameLabels [*] [*] s t, HAllTaggedLV t, HAllTaggedLV s, Functor f) => (b -> f b) -> TIP s -> f (TIP t)
- tipyLens' :: (HAllTaggedEq t, HLabelSet [*] (LabelsOf t), HasField * b (Record t) b, HUpdateAtLabel2 * b b t t, SameLength' * * t t, SameLabels [*] [*] t t, HAllTaggedLV t, Functor f) => (b -> f b) -> TIP t -> f (TIP t)
- tipyProject :: (HAllTaggedEq l, HLabelSet [*] (LabelsOf l), H2ProjectByLabels ls r l b, HAllTaggedLV l) => proxy ls -> TIP r -> TIP l
- tipyProject2 :: (HAllTaggedEq l1, HAllTaggedEq l, HLabelSet [*] (LabelsOf l), HLabelSet [*] (LabelsOf l1), H2ProjectByLabels ls r l l1, HAllTaggedLV l1, HAllTaggedLV l) => proxy ls -> TIP r -> (TIP l, TIP l1)
- tipyTuple :: (HOccurs l1 (r v1), HOccurs l1 (r v), HOccurs l (r v2), HOccurs l (r v), HDeleteAtLabel * r l1 v1 v', HDeleteAtLabel * r l1 v v2, HDeleteAtLabel * r l v2 v'1, HDeleteAtLabel * r l v v1) => r v -> (l, l1)
- tipyTuple3 :: (HOccurs l2 (r v5), HOccurs l2 (r v2), HOccurs l2 (r v), HOccurs l1 (r v4), HOccurs l1 (r v1), HOccurs l1 (r v), HOccurs l (r v6), HOccurs l (r v3), HOccurs l (r v), HDeleteAtLabel * r l2 v5 v6, HDeleteAtLabel * r l2 v2 v', HDeleteAtLabel * r l2 v v3, HDeleteAtLabel * r l1 v4 v'1, HDeleteAtLabel * r l1 v1 v2, HDeleteAtLabel * r l1 v v5, HDeleteAtLabel * r l v6 v'2, HDeleteAtLabel * r l v3 v4, HDeleteAtLabel * r l v v1) => r v -> (l, l1, l2)
- tipyTuple4 :: (HOccurs l3 (r v11), HOccurs l3 (r v7), HOccurs l3 (r v3), HOccurs l3 (r v), HOccurs l2 (r v10), HOccurs l2 (r v6), HOccurs l2 (r v2), HOccurs l2 (r v), HOccurs l1 (r v9), HOccurs l1 (r v5), HOccurs l1 (r v1), HOccurs l1 (r v), HOccurs l (r v12), HOccurs l (r v8), HOccurs l (r v4), HOccurs l (r v), HDeleteAtLabel * r l3 v11 v12, HDeleteAtLabel * r l3 v7 v8, HDeleteAtLabel * r l3 v3 v', HDeleteAtLabel * r l3 v v4, HDeleteAtLabel * r l2 v10 v11, HDeleteAtLabel * r l2 v6 v'1, HDeleteAtLabel * r l2 v2 v3, HDeleteAtLabel * r l2 v v7, HDeleteAtLabel * r l1 v9 v'2, HDeleteAtLabel * r l1 v5 v6, HDeleteAtLabel * r l1 v1 v2, HDeleteAtLabel * r l1 v v10, HDeleteAtLabel * r l v12 v'3, HDeleteAtLabel * r l v8 v9, HDeleteAtLabel * r l v4 v5, HDeleteAtLabel * r l v v1) => r v -> (l, l1, l2, l3)
- tipyTuple5 :: (HOccurs l4 (r v19), HOccurs l4 (r v14), HOccurs l4 (r v9), HOccurs l4 (r v4), HOccurs l4 (r v), HOccurs l3 (r v18), HOccurs l3 (r v13), HOccurs l3 (r v8), HOccurs l3 (r v3), HOccurs l3 (r v), HOccurs l2 (r v17), HOccurs l2 (r v12), HOccurs l2 (r v7), HOccurs l2 (r v2), HOccurs l2 (r v), HOccurs l1 (r v16), HOccurs l1 (r v11), HOccurs l1 (r v6), HOccurs l1 (r v1), HOccurs l1 (r v), HOccurs l (r v20), HOccurs l (r v15), HOccurs l (r v10), HOccurs l (r v5), HOccurs l (r v), HDeleteAtLabel * r l4 v19 v20, HDeleteAtLabel * r l4 v14 v15, HDeleteAtLabel * r l4 v9 v10, HDeleteAtLabel * r l4 v4 v', HDeleteAtLabel * r l4 v v5, HDeleteAtLabel * r l3 v18 v19, HDeleteAtLabel * r l3 v13 v14, HDeleteAtLabel * r l3 v8 v'1, HDeleteAtLabel * r l3 v3 v4, HDeleteAtLabel * r l3 v v9, HDeleteAtLabel * r l2 v17 v18, HDeleteAtLabel * r l2 v12 v'2, HDeleteAtLabel * r l2 v7 v8, HDeleteAtLabel * r l2 v2 v3, HDeleteAtLabel * r l2 v v13, HDeleteAtLabel * r l1 v16 v'3, HDeleteAtLabel * r l1 v11 v12, HDeleteAtLabel * r l1 v6 v7, HDeleteAtLabel * r l1 v1 v2, HDeleteAtLabel * r l1 v v17, HDeleteAtLabel * r l v20 v'4, HDeleteAtLabel * r l v15 v16, HDeleteAtLabel * r l v10 v11, HDeleteAtLabel * r l v5 v6, HDeleteAtLabel * r l v v1) => r v -> (l, l1, l2, l3, l4)
- type TagUntag xs = TagUntagFD xs (TagR xs)
- class SameLength a ta => TagUntagFD a ta | a -> ta, ta -> a where
- type family TagR a :: [*]
- class TransTIP op db where
- class Monad m => TransTIPM m op db where
- data TIC l
- mkTIC :: (HAllTaggedEq l, HLabelSet [*] (LabelsOf l), HasField * i (Record l) i, HFind1 * i (UnLabel * i (LabelsOf l)) n, HAllTaggedLV l, KnownNat (HNat2Nat n)) => i -> TIC l
- mkTIC1 :: forall i. MkVariant i i `[Tagged i i]` => i -> TIC `[Tagged i i]`
- mkTIC' :: forall i l proxy. (HTypeIndexed l, MkVariant i i l) => i -> proxy l -> TIC l
- ticPrism :: (TICPrism s t a b, SameLength s t, Choice p, Applicative f) => (a `p` f b) -> TIC s `p` f (TIC t)
- ticPrism' :: forall s t a b. (HPrism a s t a b, a ~ b, s ~ t) => forall f p. (Applicative f, Choice p) => (a `p` f b) -> TIC s `p` f (TIC t)
- data Variant vs
- mkVariant :: MkVariant x v vs => Label x -> v -> proxy vs -> Variant vs
- mkVariant1 :: Label k l -> e -> Variant ((:) * (Tagged k l e) ([] *))
- castVariant :: (RecordValuesR v ~ RecordValuesR v', SameLength v v') => Variant v -> Variant v'
- newtype HMapV f = HMapV f
- hMapV :: (HMapAux Variant (HFmap f) x y, SameLength' * * y x, SameLength' * * x y) => f -> Variant x -> Variant y
- hMapOutV :: forall x y z f. (SameLength x y, HMapAux Variant (HFmap f) x y, Unvariant y z, HMapOutV_gety x z ~ y) => f -> Variant x -> z
- class ZipVariant x y xy | x y -> xy, xy -> x y where
- zipVariant :: Variant x -> Variant y -> Maybe (Variant xy)
- class (SameLength v v', SameLabels v v') => ZipVR fs v v' | fs v -> v' where
- zipVR :: (SameLabels fs v, SameLength fs v, ZipVR fs v v', ZipVRCxt fs v v') => Record fs -> Variant v -> Variant v'
- class (ProjectVariant x yin, ProjectVariant x yout) => SplitVariant x yin yout where
- splitVariant :: Variant x -> Either (Variant yin) (Variant yout)
- class ProjectVariant x y where
- projectVariant :: Variant x -> Maybe (Variant y)
- class (HAllTaggedLV y, HAllTaggedLV x) => ExtendsVariant x y where
- extendsVariant :: Variant x -> Variant y
- class HAllTaggedLV y => ProjectExtendVariant x y where
- projectExtendVariant :: Variant x -> Maybe (Variant y)
- class (SameLength s t, SameLabels s t) => HPrism x s t a b | x s -> a, x t -> b, x s b -> t, x t a -> s where
- unvarianted :: (Unvariant' s a, Unvariant' t b, SameLabels s t, SameLength s t, Functor f) => (a -> f b) -> Variant s -> f (Variant t)
- unvarianted' :: (HAllEqVal ((:) * (Tagged * () b) s) b1, HAllEqVal s b1, HAllEqVal' ((:) * (Tagged * () b) s), Unvariant1 Bool b1 s b, SameLength' * * s s, SameLabels [*] [*] s s, Functor f) => (b -> f b) -> Variant s -> f (Variant s)
- splitVariant1 :: Variant (Tagged s x : xs) -> Either x (Variant xs)
- splitVariant1' :: Variant (x : xs) -> Either x (Variant xs)
- extendVariant :: Variant l -> Variant (e : l)
- class Unvariant v e | v -> e where
- class Unvariant' v e | v -> e where
- unvariant' :: Variant v -> e
- class TypeIndexed r tr | r -> tr, tr -> r where
- typeIndexed :: forall p f s t a b. (TypeIndexedCxt s t a b, Profunctor p, Functor f) => p (tr (TagR a)) (f (tr (TagR b))) -> p (r s) (f (r t))
- typeIndexed' :: (TypeIndexed r tr, TagUntagFD (RecordValuesR s) (TagR (RecordValuesR s)), HLabelSet [*] (LabelsOf s), RecordValues s, HMapAux HList TaggedFn (RecordValuesR s) s, SameLength' * * (RecordValuesR s) (RecordValuesR s), SameLength' * * s s, SameLabels [*] [*] s s, HAllTaggedLV s, Profunctor p, Coercible [*] (TagR (RecordValuesR s)) s, Functor f) => p (tr (TagR (RecordValuesR s))) (f (tr (TagR (RecordValuesR s)))) -> p (r s) (f (r s))
- tipHList :: (TagUntagFD a1 l, TagUntagFD a ta, Profunctor p, Functor f) => p (HList a) (f (HList a1)) -> p (TIP ta) (f (TIP l))
- tipHList' :: (TagUntagFD a ta, Profunctor p, Functor f) => p (HList a) (f (HList a)) -> p (TIP ta) (f (TIP ta))
- unboxed :: forall x y f p. (Profunctor p, Functor f, RecordToRecordU x, RecordUToRecord y) => (RecordU x `p` f (RecordU y)) -> Record x `p` f (Record y)
- unboxed' :: (RecordValues x, HMapAux HList TaggedFn (RecordValuesR x) x, HList2List (RecordValuesR x) (GetElemTy x), HLengthEq1 HNat x n, HLengthEq2 HNat x n, SameLength' * * (HReplicateR * n ()) x, Profunctor p, IArray UArray (GetElemTy x), KnownNat (HNat2Nat n), Functor f) => p (RecordU x) (f (RecordU x)) -> p (Record x) (f (Record x))
- unboxedS :: (HMapUnboxF g1 u1, HMapUnboxF g u, HConcatFD g1 x1, HMapAux HList UnboxF g u, HMapAux HList BoxF u1 g1, HGroupBy * EqTagValue x1 g1, HGroupBy * EqTagValue x g, SameLength' * * g1 u1, SameLength' * * g u, SameLength' * * u1 g1, SameLength' * * u g, Profunctor p, Functor f) => p (RecordUS x) (f (RecordUS x1)) -> p (Record x) (f (Record x1))
- unboxedS' :: (HMapUnboxF g u, HConcatFD g x, HMapAux HList UnboxF g u, HMapAux HList BoxF u g, HGroupBy * EqTagValue x g, SameLength' * * g u, SameLength' * * u g, Profunctor p, Functor f) => p (RecordUS x) (f (RecordUS x)) -> p (Record x) (f (Record x))
- hMaybied :: (VariantToHMaybied v1 x, VariantToHMaybied v r, HFoldr HMaybiedToVariantFs [Variant ([] *)] x [Variant v1], HMapAux HList (HFmap HCastF) x r, SameLength' * * x r, SameLength' * * r x, Choice p, Applicative f) => p (Variant v1) (f (Variant v)) -> p (Record x) (f (Record r))
- hMaybied' :: (VariantToHMaybied v x, HFoldr HMaybiedToVariantFs [Variant ([] *)] x [Variant v], HMapAux HList (HFmap HCastF) x x, SameLength' * * x x, Choice p, Applicative f) => p (Variant v) (f (Variant v)) -> p (Record x) (f (Record x))
- ticVariant :: (Profunctor p, Functor f) => p (Variant t) (f (Variant l)) -> p (TIC t) (f (TIC l))
- ticVariant' :: (Profunctor p, Functor f) => p (Variant t) (f (Variant t)) -> p (TIC t) (f (TIC t))
- tipRecord :: (Profunctor p, Functor f) => p (Record r) (f (Record l)) -> p (TIP r) (f (TIP l))
- tipRecord' :: (Profunctor p, Functor f) => p (Record r) (f (Record r)) -> p (TIP r) (f (TIP r))
- class VariantToHMaybied v r | v -> r, r -> v where
- variantToHMaybied :: Variant v -> Record r
- data HMaybiedToVariantFs
- hMaybiedToVariants :: (HFoldr HMaybiedToVariantFs [Variant []] r [Variant v], VariantToHMaybied v r) => Record r -> [Variant v]
- class Kw fn arg_def r where
- recToKW :: forall a b. (HMapCxt HList TaggedToKW a b, HConcat b) => Record a -> HList (HConcatR b)
- class IsKeyFN t flag | t -> flag
- data K s c
- data ErrReqdArgNotFound x
- data ErrUnexpectedKW x
- module Data.HList.Labelable
- module Data.HList.Label3
- module Data.HList.MakeLabels
- module Data.HList.TypeEqO
- class HAllTaggedEq l
Faking dependent types in Haskell
module Data.HList.FakePrelude
Functions for all collections
module Data.HList.HListPrelude
Array-like access to HLists
module Data.HList.HArray
Result-type-driven operations
module Data.HList.HOccurs
Type-indexed operations
module Data.HList.HTypeIndexed
Record
module Data.HList.Record
quasiquoter pun
helps to avoid needing a proxy value with
type Label
in the first place: when you take values out of or into
records with pattern matching, the variable name determines the label
name.
module Data.HList.RecordPuns
Unpacked / Unboxed Records
A type which behaves similarly to Record
, except
all elements must fit in the same UArray
. A consequence of
this is that RecordU
has the following properties:
- it is strict in the element types
- it cannot do type-changing updates of
RecordU
, except if the function applies to all elements - it probably is slower to update the very first elements
of the
RecordU
The benefit is that lookups should be faster and records
should take up less space. However benchmarks done with
a slow HNat2Integral
do not suggest that RecordU is
faster than Record.
RecordUS
is stored as a HList
of RecordU
to allow the RecordUS
to contain elements of different
types, so long all of the types can be put into an unboxed
array (UArray
).
It is advantageous (at least space-wise) to sort the record to keep
elements with the same types elements adjacent. See SortForRecordUS
for more details.
(HFindLabel k l r n, HLookupByHNatUS n u (Tagged k l v), HasField k l (Record r) v, RecordUSCxt r u) => HasField k l (RecordUS r) v | works expected. See examples attached to |
(RecordUSCxt x u, Show (HList u)) => Show (RecordUS x) |
class SortForRecordUS x x' | x -> x' where Source
Reorders a Record
such that the RecordUS
made from it takes up
less space
Bad
has alternating Double and Int fields
>>>
bad
Record{x=1.0,i=2,y=3.0,j=4}
4 arrays containing one element each are needed when this Record is stored as a RecordUS
>>>
recordToRecordUS bad
RecordUS H[RecordU (array (0,0) [(0,1.0)]),RecordU (array (0,0) [(0,2)]),RecordU (array (0,0) [(0,3.0)]),RecordU (array (0,0) [(0,4)])]
It is possible to sort the record
>>>
sortForRecordUS bad
Record{x=1.0,y=3.0,i=2,j=4}
This allows the same content to be stored in two unboxed arrays
>>>
recordToRecordUS (sortForRecordUS bad)
RecordUS H[RecordU (array (0,1) [(0,1.0),(1,3.0)]),RecordU (array (0,1) [(0,2),(1,4)])]
sortForRecordUS :: Record x -> Record x' Source
SortForRecordUS ([] *) ([] *) | |
(HPartitionEq * * EqTagValue x ((:) * x xs) xi xo, SortForRecordUS xo xo', (~) [*] sorted (HAppendListR * xi xo'), HAppendList xi xo') => SortForRecordUS ((:) * x xs) sorted |
class HUpdateMany lv rx where Source
analogous flip //
. Similar to .<++.
, except it is restricted
to cases where the left argument holds a subset of elements.
hUpdateMany :: Record lv -> rx -> rx Source
(HLeftUnion lv x lvx, HRLabelSet x, HLabelSet [*] (LabelsOf x), HRearrange (LabelsOf x) lvx x) => HUpdateMany lv (Record x) | implementation in terms of |
(RecordValues lv, HList2List (RecordValuesR lv) v, HFindMany * (LabelsOf lv) (LabelsOf r) ixs, IArray UArray v, (~) * v (GetElemTy r), HNats2Integrals ixs) => HUpdateMany lv (RecordU r) |
internals for types
class HNats2Integrals ns where Source
hNats2Integrals :: Integral i => Proxy ns -> [i] Source
HNats2Integrals ([] HNat) | |
(HNats2Integrals ns, HNat2Integral n) => HNats2Integrals ((:) HNat n ns) |
class RecordUSCxt x u | x -> u, u -> x Source
connect the unpacked x
representation with the
corresponding list of RecordU u
representation.
(HGroupBy * EqTagValue x g, HMapUnboxF g u) => RecordUSCxt x u | the only instance |
class HLookupByHNatUS n us e | n us -> e Source
((~) (Either HNat HNat) r (HSubtract (HLength * u) n), (~) * (RecordU u) ru, HLookupByHNatUS1 r n u us e) => HLookupByHNatUS n ((:) * ru us) e |
class HLookupByHNatUS1 r n u us e | r n u us -> e Source
(HNat2Integral n, (~) * (HLookupByHNatR n u) le, (~) * le (Tagged k l e), IArray UArray e, (~) * e (GetElemTy u)) => HLookupByHNatUS1 (Left HNat HNat t) n u us le | |
HLookupByHNatUS t us e => HLookupByHNatUS1 (Right HNat HNat t) n u us e |
type family HSubtract n1 n2 :: Either HNat HNat Source
HSubtract a b
is Left (a-b)
, Right (b-a)
or Right HZero
class HMapUnboxF xs us | xs -> us, us -> xs Source
HMapUnboxF ([] *) ([] *) | |
HMapUnboxF xs us => HMapUnboxF ((:) * (HList x) xs) ((:) * (RecordU x) us) |
((~) * hx (HList x), (~) * ux (RecordU x), RecordToRecordU x) => ApplyAB UnboxF hx ux |
data EqTagValue Source
HEqByFn * EqTagValue | |
((~) * txv (Tagged k x v), (~) * tyw (Tagged k1 y w), HEq * v w b) => HEqBy * * EqTagValue txv tyw b |
all elements of the list have the same type
class RecordToRecordU x Source
(RecordValues x, HList2List (RecordValuesR x) (GetElemTy x), HNat2Integral n, HLengthEq x n, IArray UArray (GetElemTy x)) => RecordToRecordU x |
class RecordUToRecord x Source
(HMapCxt HList TaggedFn (RecordValuesR x) x, IArray UArray (GetElemTy x), HList2List (RecordValuesR x) (GetElemTy x)) => RecordUToRecord x |
HList
A subset of Data.HList.HList is re-exported.
module Data.HList.HList
module Data.HList.HZip
A subset of Data.HList.HSort
class (SameLength a b, HEqByFn le) => HSortBy le a b | le a -> b where Source
quick sort with a special case for sorted lists
(SameLength * * a b, HIsAscList k le a ok, HSortBy1 Bool k ok le a b) => HSortBy k le a b |
the "standard" <=
for types. Reuses HEqBy
Note that ghc-7.6 is missing instances for Symbol and Nat, so that
sorting only works HNat
(as used by Data.HList.Label3).
HEqByFn * HLeFn | |
(~) Bool ((<=?) x y) b => HEqBy * Nat HLeFn x y b | only in ghc >= 7.7 |
(HEq Ordering (CmpSymbol x y) GT nb, (~) Bool (HNot nb) b) => HEqBy * Symbol HLeFn x y b | only in ghc >= 7.7
|
(~) Bool (HLe x y) b => HEqBy * HNat HLeFn x y b | |
HEqBy * k HLeFn x y b => HEqBy * * HLeFn (Proxy k x) (Proxy k y) b | |
HEqBy * k HLeFn x y b => HEqBy * * HLeFn (Label k x) (Label k y) b | |
HEqBy * k HLeFn x y b => HEqBy * * HLeFn (Tagged k x v) (Tagged k y w) b | |
(HEqBy * HNat HLeFn n m b, (~) * ns ns') => HEqBy * * HLeFn (Lbl n ns desc) (Lbl m ns' desc') b | Data.HList.Label3 labels can only be compared if they belong to the same namespace. |
analogous to Down
class HEqByFn lt => HSetBy lt ps Source
Provided the labels involved have an appropriate instance of HEqByFn, it would be possible to use the following definitions:
type HRLabelSet = HSet type HLabelSet = HSet
class HIsSet ps b | ps -> b Source
>>>
let xx = Proxy :: HIsSet [Label "x", Label "x"] b => Proxy b
>>>
:t xx
xx :: Proxy 'False
>>>
let xy = Proxy :: HIsSet [Label "x", Label "y"] b => Proxy b
>>>
:t xy
xy :: Proxy 'True
class HEqByFn lt => HIsSetBy lt ps b | lt ps -> b Source
(HSortBy k lt ps ps', HIsAscList k lt ps' b) => HIsSetBy k lt ps b |
class HEqByFn le => HAscList le ps Source
HAscList le xs
confirms that xs is in ascending order,
and reports which element is duplicated otherwise.
class HEqByFn le => HIsAscList le xs b | le xs -> b Source
HIsAscList le xs b
is analogous to
b = all (\(x,y) -> x `le` y) (xs `zip` tail xs)
HEqByFn k le => HIsAscList k le ([] *) True | |
(HEqBy k * le x y b1, HIsAscList k le ((:) * y ys) b2, (~) Bool (HAnd b1 b2) b3) => HIsAscList k le ((:) * x ((:) * y ys)) b3 | |
HEqByFn k le => HIsAscList k le ((:) * x ([] *)) True |
A subset of Data.HList.HCurry
class HLengthEq xs n => HCurry' n f xs r | f xs -> r, r xs -> f, n f -> xs, xs -> n where Source
'curry'/'uncurry' for many arguments and HLists instead of tuples
XXX the last FD xs -> n
is needed to make hCompose infer the right types:
arguably it shouldn't be needed
hCurry :: (HCurry' n f xs r, ArityFwd f n, ArityRev f n) => (HList xs -> r) -> f Source
Note: with ghc-7.10 the Arity constraint added here does not work
properly with hCompose, so it is possible that other uses of hCurry
are better served by hCurry' Proxy
.
hCompose :: (HCurry' n2 f2 xs1 r, HCurry' n1 f1 xs x, HCurry' n f xsys r, HSplitAt1 ([] *) n1 xsys xs xs1, HAppendList1 * xs xs1 xsys, ArityFwd f2 n2, ArityFwd f1 n1, ArityRev f2 n2, ArityRev f1 n1) => (x -> f2) -> f1 -> f Source
compose two functions that take multiple arguments. The result of the second function is the first argument to the first function. An example is probably clearer:
>>>
let f = hCompose (,,) (,)
>>>
:t f
f :: ... -> ... -> ... -> ... -> ((..., ...), ..., ...)
>>>
f 1 2 3 4
((1,2),3,4)
Note: polymorphism can make it confusing as to how many parameters a function
actually takes. For example, the first two ids are id :: (a -> b) -> (a -> b)
in
>>>
(.) id id id 'y'
'y'
>>>
hCompose id id id 'y'
'y'
still typechecks, but in that case hCompose i1 i2 i3 x == i1 ((i2 i3) x)
has id with different types than @(.) i1 i2 i3 x == (i1 (i2 i3)) x
Prompted by http://stackoverflow.com/questions/28932054/can-hlistelim-be-composed-with-another-function
TIP
Public interface of Data.HList.TIP
TIPs are like Record
, except element "i" of the list "l"
has type Tagged e_i e_i
TypeIndexed Record TIP | |
(HZipList (UntagR x) (UntagR y) (UntagR xy), UntagTag x, UntagTag y, UntagTag xy, SameLengths * ((:) [*] x ((:) [*] y ((:) [*] xy ([] [*])))), HTypeIndexed x, HTypeIndexed y, HUnzip TIP x y xy) => HZip TIP x y xy | |
(HZipList (UntagR x) (UntagR y) (UntagR xy), UntagTag x, UntagTag y, UntagTag xy, HTypeIndexed x, HTypeIndexed y, SameLengths * ((:) [*] x ((:) [*] y ((:) [*] xy ([] [*]))))) => HUnzip TIP x y xy | |
(HDeleteAtLabel k Record e v v', HTypeIndexed v') => HDeleteAtLabel k TIP e v v' | |
(HUpdateAtLabel * Record e' e r r', HTypeIndexed r', (~) * e e') => HUpdateAtLabel * TIP e' e r r' | |
LabelableTIPCxt x s t a b => Labelable * x TIP s t a b | make a
|
((~) * e e', HasField * e (Record l) e') => HasField * e (TIP l) e' | |
(HOccurs e (TIP l1), SubType * * (TIP l1) (TIP l2)) => SubType * * (TIP l1) (TIP ((:) * e l2)) | |
SubType * * (TIP l) (TIP ([] *)) | Subtyping for TIPs |
HasField * e (Record ((:) * x ((:) * y l))) e => HOccurs e (TIP ((:) * x ((:) * y l))) | |
(~) * tee (Tagged * e e) => HOccurs e (TIP ((:) * tee ([] *))) | One occurrence and nothing is left This variation provides an extra feature for singleton lists. That is, the result type is unified with the element in the list. Hence the explicit provision of a result type can be omitted. |
(HRLabelSet ((:) * (Tagged * e e) l), HTypeIndexed l) => HExtend e (TIP l) | |
Bounded (HList r) => Bounded (TIP r) | |
Eq (HList a) => Eq (TIP a) | |
(TypeablePolyK [*] xs, Typeable * (HList xs), Data (HList xs)) => Data (TIP xs) | |
Ord (HList r) => Ord (TIP r) | |
HMapOut (HComp HShow HUntag) l String => Show (TIP l) | |
Ix (HList r) => Ix (TIP r) | |
Monoid (HList a) => Monoid (TIP a) | |
(HAppend (HList l) (HList l'), HTypeIndexed (HAppendListR * l l')) => HAppend (TIP l) (TIP l') | |
Typeable ([*] -> *) TIP | |
type LabelableTy TIP = LabelableLens | |
type HExtendR e (TIP l) = TIP ((:) * (Tagged * e e) l) | |
type HAppendR * (TIP l) (TIP l') = TIP (HAppendListR * l l') |
tipyUpdate :: (HUpdateAtLabel * record v v r r, SameLength' * * r r) => v -> record r -> record r Source
tipyLens :: (HAllTaggedEq t, HAllTaggedEq s, HLabelSet [*] (LabelsOf t), HLabelSet [*] (LabelsOf s), HasField * b (Record t) b, HasField * b (Record s) b, HUpdateAtLabel2 * b b t s, HUpdateAtLabel2 * b b s t, SameLength' * * t s, SameLength' * * s t, SameLabels [*] [*] s t, HAllTaggedLV t, HAllTaggedLV s, Functor f) => (b -> f b) -> TIP s -> f (TIP t) Source
provides a Lens (TIP s) (TIP t) a b
When using set
(also known as .~
), tipyLens'
can address the
ambiguity as to which field "a" should actually be updated.
tipyLens' :: (HAllTaggedEq t, HLabelSet [*] (LabelsOf t), HasField * b (Record t) b, HUpdateAtLabel2 * b b t t, SameLength' * * t t, SameLabels [*] [*] t t, HAllTaggedLV t, Functor f) => (b -> f b) -> TIP t -> f (TIP t) Source
provides a Lens' (TIP s) a
. hLens'
:: Label a -> Lens' (TIP s) a
is another option.
projection
tipyProject :: (HAllTaggedEq l, HLabelSet [*] (LabelsOf l), H2ProjectByLabels ls r l b, HAllTaggedLV l) => proxy ls -> TIP r -> TIP l Source
Use Labels
to specify the first argument
tipyProject2 :: (HAllTaggedEq l1, HAllTaggedEq l, HLabelSet [*] (LabelsOf l), HLabelSet [*] (LabelsOf l1), H2ProjectByLabels ls r l l1, HAllTaggedLV l1, HAllTaggedLV l) => proxy ls -> TIP r -> (TIP l, TIP l1) Source
The same as tipyProject
, except also return the
types not requested in the proxy
argument
tipyTuple :: (HOccurs l1 (r v1), HOccurs l1 (r v), HOccurs l (r v2), HOccurs l (r v), HDeleteAtLabel * r l1 v1 v', HDeleteAtLabel * r l1 v v2, HDeleteAtLabel * r l v2 v'1, HDeleteAtLabel * r l v v1) => r v -> (l, l1) Source
project a TIP (or HList) into a tuple
tipyTuple' x = (hOccurs
x, hOccurs x)
behaves similarly, except tipyTuple
excludes
the possibility of looking up the same element
twice, which allows inferring a concrete type
in more situations. For example
(\x y z -> tipyTuple (x .*. y .*. emptyTIP) `asTypeOf` (x, z)) () 'x'
has type Char -> ((), Char)
. tipyTuple' would
need a type annotation to decide whether the type
should be Char -> ((), Char)
or () -> ((), ())
tipyTuple3 :: (HOccurs l2 (r v5), HOccurs l2 (r v2), HOccurs l2 (r v), HOccurs l1 (r v4), HOccurs l1 (r v1), HOccurs l1 (r v), HOccurs l (r v6), HOccurs l (r v3), HOccurs l (r v), HDeleteAtLabel * r l2 v5 v6, HDeleteAtLabel * r l2 v2 v', HDeleteAtLabel * r l2 v v3, HDeleteAtLabel * r l1 v4 v'1, HDeleteAtLabel * r l1 v1 v2, HDeleteAtLabel * r l1 v v5, HDeleteAtLabel * r l v6 v'2, HDeleteAtLabel * r l v3 v4, HDeleteAtLabel * r l v v1) => r v -> (l, l1, l2) Source
tipyTuple4 :: (HOccurs l3 (r v11), HOccurs l3 (r v7), HOccurs l3 (r v3), HOccurs l3 (r v), HOccurs l2 (r v10), HOccurs l2 (r v6), HOccurs l2 (r v2), HOccurs l2 (r v), HOccurs l1 (r v9), HOccurs l1 (r v5), HOccurs l1 (r v1), HOccurs l1 (r v), HOccurs l (r v12), HOccurs l (r v8), HOccurs l (r v4), HOccurs l (r v), HDeleteAtLabel * r l3 v11 v12, HDeleteAtLabel * r l3 v7 v8, HDeleteAtLabel * r l3 v3 v', HDeleteAtLabel * r l3 v v4, HDeleteAtLabel * r l2 v10 v11, HDeleteAtLabel * r l2 v6 v'1, HDeleteAtLabel * r l2 v2 v3, HDeleteAtLabel * r l2 v v7, HDeleteAtLabel * r l1 v9 v'2, HDeleteAtLabel * r l1 v5 v6, HDeleteAtLabel * r l1 v1 v2, HDeleteAtLabel * r l1 v v10, HDeleteAtLabel * r l v12 v'3, HDeleteAtLabel * r l v8 v9, HDeleteAtLabel * r l v4 v5, HDeleteAtLabel * r l v v1) => r v -> (l, l1, l2, l3) Source
tipyTuple5 :: (HOccurs l4 (r v19), HOccurs l4 (r v14), HOccurs l4 (r v9), HOccurs l4 (r v4), HOccurs l4 (r v), HOccurs l3 (r v18), HOccurs l3 (r v13), HOccurs l3 (r v8), HOccurs l3 (r v3), HOccurs l3 (r v), HOccurs l2 (r v17), HOccurs l2 (r v12), HOccurs l2 (r v7), HOccurs l2 (r v2), HOccurs l2 (r v), HOccurs l1 (r v16), HOccurs l1 (r v11), HOccurs l1 (r v6), HOccurs l1 (r v1), HOccurs l1 (r v), HOccurs l (r v20), HOccurs l (r v15), HOccurs l (r v10), HOccurs l (r v5), HOccurs l (r v), HDeleteAtLabel * r l4 v19 v20, HDeleteAtLabel * r l4 v14 v15, HDeleteAtLabel * r l4 v9 v10, HDeleteAtLabel * r l4 v4 v', HDeleteAtLabel * r l4 v v5, HDeleteAtLabel * r l3 v18 v19, HDeleteAtLabel * r l3 v13 v14, HDeleteAtLabel * r l3 v8 v'1, HDeleteAtLabel * r l3 v3 v4, HDeleteAtLabel * r l3 v v9, HDeleteAtLabel * r l2 v17 v18, HDeleteAtLabel * r l2 v12 v'2, HDeleteAtLabel * r l2 v7 v8, HDeleteAtLabel * r l2 v2 v3, HDeleteAtLabel * r l2 v v13, HDeleteAtLabel * r l1 v16 v'3, HDeleteAtLabel * r l1 v11 v12, HDeleteAtLabel * r l1 v6 v7, HDeleteAtLabel * r l1 v1 v2, HDeleteAtLabel * r l1 v v17, HDeleteAtLabel * r l v20 v'4, HDeleteAtLabel * r l v15 v16, HDeleteAtLabel * r l v10 v11, HDeleteAtLabel * r l v5 v6, HDeleteAtLabel * r l v v1) => r v -> (l, l1, l2, l3, l4) Source
type TagUntag xs = TagUntagFD xs (TagR xs) Source
class SameLength a ta => TagUntagFD a ta | a -> ta, ta -> a where Source
TagR
can also be used to avoid redundancy when defining types for TIC and TIP.
type XShort = TagR [A,B,C,D]
type XLong = [Tagged A A, Tagged B B, Tagged C C, Tagged D D]
an equivalent FD version, which is slightly better with respect to simplifying types containing type variables (in ghc-7.8 and 7.6): http://stackoverflow.com/questions/24110410/
With ghc-7.10 (http://ghc.haskell.org/trac/ghc/ticket/10009) the FD version is superior to the TF version:
class (UntagR (TagR a) ~ a) => TagUntag a where type TagR a :: [*] hTagSelf :: HList a -> HList (TagR a) hUntagSelf :: HList (TagR a) -> HList a instance TagUntag '[] where type TagR '[] = '[] hTagSelf _ = HNil hUntagSelf _ = HNil instance TagUntag xs => TagUntag (x ': xs) where type TagR (x ': xs) = Tagged x x ': TagR xs hTagSelf (HCons x xs) = Tagged xHCons
hTagSelf xs hUntagSelf (HCons (Tagged x) xs) = xHCons
hUntagSelf xs type family UntagR (xs :: [*]) :: [*] type instance UntagR '[] = '[] type instance UntagR (x ': xs) = Untag1 x ': UntagR xs
Length information should flow backwards
>>>
let len2 x = x `asTypeOf` (undefined :: HList '[a,b])
>>>
let f = len2 $ hTagSelf (hReplicate Proxy ())
>>>
:t f
f :: HList '[Tagged () (), Tagged () ()]
TagUntagFD ([] *) ([] *) | |
(TagUntagFD xs ys, (~) * txx (Tagged * x x)) => TagUntagFD ((:) * x xs) ((:) * txx ys) |
TIP transform
class TransTIP op db where Source
Transforming a TIP: applying to a TIP a (polyvariadic) function that takes arguments from a TIP and updates the TIP with the result.
In more detail: we have a typed-indexed collection TIP and we would like to apply a transformation function to it, whose argument types and the result type are all in the TIP. The function should locate its arguments based on their types, and update the TIP with the result. The function may have any number of arguments, including zero; the order of arguments should not matter.
The problem was posed by Andrew U. Frank on Haskell-Cafe, Sep 10, 2009. http://www.haskell.org/pipermail/haskell-cafe/2009-September/066217.html The problem is an interesting variation of the keyword argument problem.
Examples can be found in examples/TIPTransform.hs
and examples/TIPTransformM.hs
class Monad m => TransTIPM m op db where Source
In March 2010, Andrew Frank extended the problem for monadic operations.
This is the monadic version of TIPTransform.hs
in the present directory.
This is the TF implementation. When specifying the operation to perform over a TIP, we can leave it polymorphic over the monad. The type checker will instantiate the monad based on the context.
TIC
Public interface of Data.HList.TIC
A datatype for type-indexed co-products. A TIC
is just a Variant
,
where the elements of the type-level list "l"
are in the form
Tagged x x
.
TypeIndexed Variant TIC | |
HMapAux Variant f xs ys => HMapAux TIC f xs ys | |
(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 |
HasField * o (Variant l) (Maybe o) => HasField * o (TIC l) (Maybe o) | Public destructor (or, open union's projection function) |
(HasField * o (TIC l) mo, (~) * mo (Maybe o)) => HOccurs mo (TIC l) | |
((~) * me (Maybe e), HOccursNot * (Tagged * e e) l) => HExtend me (TIC l) | Nothing .*. x = x Just a .*. y = mkTIC a |
Bounded (Variant l) => Bounded (TIC l) | |
Enum (Variant l) => Enum (TIC l) | |
Eq (Variant l) => Eq (TIC l) | |
(TypeablePolyK [*] xs, Typeable * (Variant xs), Data (Variant xs)) => Data (TIC xs) | |
Ord (Variant l) => Ord (TIC l) | |
(ReadVariant l, HAllTaggedEq l, HRLabelSet l) => Read (TIC l) | |
ShowVariant l => Show (TIC l) | TICs are not opaque |
Ix (Variant l) => Ix (TIC l) | |
Monoid (Variant l) => Monoid (TIC l) | |
Typeable ([*] -> *) TIC | |
type LabelableTy TIC = LabelablePrism | |
type HExtendR me (TIC l) = TIC ((:) * (Tagged * (UnMaybe me) (UnMaybe me)) l) |
creating TIC
mkTIC :: (HAllTaggedEq l, HLabelSet [*] (LabelsOf l), HasField * i (Record l) i, HFind1 * i (UnLabel * i (LabelsOf l)) n, HAllTaggedLV l, KnownNat (HNat2Nat n)) => i -> TIC l Source
make a TIC for use in contexts where the result type is fixed
mkTIC1 :: forall i. MkVariant i i `[Tagged i i]` => i -> TIC `[Tagged i i]` Source
make a TIC that contains one element
:: (HTypeIndexed l, MkVariant i i l) | |
=> i | |
-> proxy l | the ordering of types in the |
-> TIC l |
Public constructor (or, open union's injection function)
get,set,modify
ticPrism :: (TICPrism s t a b, SameLength s t, Choice p, Applicative f) => (a `p` f b) -> TIC s `p` f (TIC t) Source
ticPrism' :: forall s t a b. (HPrism a s t a b, a ~ b, s ~ t) => forall f p. (Applicative f, Choice p) => (a `p` f b) -> TIC s `p` f (TIC t) Source
Prism' (TIC s) a
Variant
Public interface of Data.HList.Variant
Variant vs
has an implementation similar to Dynamic
, except the
contained value is one of the elements of the vs
list, rather than
being one particular instance of Typeable
.
>>>
v .!. _right
Nothing
>>>
v .!. _left
Just 'x'
In some cases the pun
quasiquote works with variants,
>>>
let f [pun| left right |] = (left,right)
>>>
f v
(Just 'x',Nothing)
>>>
f w
(Nothing,Just 5)
>>>
let add1 v = hMapV (Fun succ :: Fun '[Enum] '()) v
>>>
f (add1 v)
(Just 'y',Nothing)
>>>
f (add1 w)
(Nothing,Just 6)
Relabeled Variant | |
TypeIndexed Variant TIC | |
(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) |
HUpdateVariantAtLabelCxt k l e v v' n _e => HUpdateAtLabel k Variant l e v v' | hUpdateAtLabel x e' (mkVariant x e proxy) == mkVariant x e' proxy hUpdateAtLabel y e' (mkVariant x e proxy) == mkVariant x e proxy |
(HPrism k x s t a b, (~) (* -> * -> *) to (->)) => Labelable k x Variant s t a b | make a |
(HasField k x (Record vs) a, HFindLabel k x vs n, HNat2Integral n) => HasField k x (Variant vs) (Maybe a) | |
(ApplyAB f te te', HMapCxt Variant f ((:) * l ls) ((:) * l' ls')) => HMapAux Variant f ((:) * te ((:) * l ls)) ((:) * te' ((:) * l' ls')) | |
ApplyAB f te te' => HMapAux Variant f ((:) * te ([] *)) ((:) * te' ([] *)) | |
((~) * le (Tagged k l (Maybe e)), HOccursNot * (Label k l) (LabelsOf v)) => HExtend le (Variant v) | Extension for Variants prefers the first value (l .=. Nothing) .*. v = v (l .=. Just e) .*. _ = mkVariant l e Proxy |
(Unvariant ((:) * txy ([] *)) txy, (~) * tx (Tagged k t x), (~) * ty (Tagged k t y), (~) * txy (Tagged k t (x, y))) => HUnzip Variant ((:) * tx ([] *)) ((:) * ty ([] *)) ((:) * txy ([] *)) | |
(HUnzip Variant ((:) * x2 xs) ((:) * y2 ys) ((:) * xy2 xys), (~) * tx (Tagged k t x), (~) * ty (Tagged k t y), (~) * txy (Tagged k t (x, y))) => HUnzip Variant ((:) * tx ((:) * x2 xs)) ((:) * ty ((:) * y2 ys)) ((:) * txy ((:) * xy2 xys)) | |
(Bounded x, Bounded z, (~) [*] (HRevAppR * ((:) * (Tagged k1 s x) xs) ([] *)) ((:) * (Tagged k t z) sx), MkVariant k t z ((:) * (Tagged k1 s x) xs)) => Bounded (Variant ((:) * (Tagged k s x) xs)) | |
Enum x => Enum (Variant ((:) * (Tagged k s x) ([] *))) | While the instances could be written Enum (Variant '[])
Eq/Ord which cannot produce values, so they have instances for
empty variants ( |
(Enum x, Bounded x, Enum (Variant ((:) * y z))) => Enum (Variant ((:) * (Tagged k s x) ((:) * y z))) |
The last type in the Variant does not need to be Bounded. This
means that
This is a "feature" because it allows an Another difficult choice is that the lower bound is
|
(Eq (Variant xs), Eq x) => Eq (Variant ((:) * x xs)) | |
Eq (Variant ([] *)) | |
(Typeable * (Variant v), GfoldlVariant v v, GunfoldVariant v v, VariantConstrs v) => Data (Variant v) | |
(Ord x, Ord (Variant xs)) => Ord (Variant ((:) * x xs)) | |
Ord (Variant ([] *)) | |
ReadVariant v => Read (Variant v) | A corresponding read instance |
ShowVariant vs => Show (Variant vs) | Variants are not opaque |
(Monoid x, Monoid (Variant ((:) * a b))) => Monoid (Variant ((:) * (Tagged k t x) ((:) * a b))) | XXX check this mappend is legal |
(Unvariant ((:) * (Tagged k t x) ([] *)) x, Monoid x) => Monoid (Variant ((:) * (Tagged k t x) ([] *))) | |
(SameLength * * s a, ExtendsVariant s a, SameLength * * b t, ExtendsVariant b t) => Rearranged [*] Variant s t a b | |
Typeable ([*] -> *) Variant | |
type LabelableTy Variant = LabelablePrism | |
type HExtendR le (Variant v) = Variant ((:) * (UnMaybe le) v) |
mkVariant1 :: Label k l -> e -> Variant ((:) * (Tagged k l e) ([] *)) Source
castVariant :: (RecordValuesR v ~ RecordValuesR v', SameLength v v') => Variant v -> Variant v' Source
in ghc>=7.8, coerce
is probably a better choice
Apply a function to all possible elements of the variant
HMapV f |
hMapV :: (HMapAux Variant (HFmap f) x y, SameLength' * * y x, SameLength' * * x y) => f -> Variant x -> Variant y Source
shortcut for applyAB . HMapV
. hMap
is more general
hMapOutV :: forall x y z f. (SameLength x y, HMapAux Variant (HFmap f) x y, Unvariant y z, HMapOutV_gety x z ~ y) => f -> Variant x -> z Source
hMapOutV f = unvariant . hMapV f
, except an ambiguous type
variable is resolved by HMapOutV_gety
class ZipVariant x y xy | x y -> xy, xy -> x y where Source
Applies to variants that have the same labels in the same order. A generalization of
zipEither :: Either a b -> Either a b -> Maybe (Either (a,a) (b,b)) zipEither (Left a) (Left a') = Just (Left (a,a')) zipEither (Right a) (Right a') = Just (Right (a,a')) zipEither _ _ = Nothing
see HZip
for zipping other collections
ZipVariant ([] *) ([] *) ([] *) | |
((~) * tx (Tagged k t x), (~) * ty (Tagged k t y), (~) * txy (Tagged k t (x, y)), ZipVariant xs ys zs, MkVariant k t (x, y) ((:) * txy zs)) => ZipVariant ((:) * tx xs) ((:) * ty ys) ((:) * txy zs) |
class (SameLength v v', SameLabels v v') => ZipVR fs v v' | fs v -> v' where Source
Apply a record of functions to a variant of values. The functions are selected based on those having the same label as the value.
zipVR :: (SameLabels fs v, SameLength fs v, ZipVR fs v v', ZipVRCxt fs v v') => Record fs -> Variant v -> Variant v' Source
>>>
let xy = x .*. y .*. emptyProxy
>>>
let p = Proxy `asLabelsOf` xy
>>>
let vs = [ mkVariant x 1.0 p, mkVariant y () p ]
>>>
zipVR (hBuild (+1) id) `map` vs
[V{x=2.0},V{y=()}]
projection
many
class (ProjectVariant x yin, ProjectVariant x yout) => SplitVariant x yin yout where Source
(ProjectVariant x yin, ProjectVariant x yout, H2ProjectByLabels (LabelsOf yin) x xi xo, HRearrange (LabelsOf yin) xi yin, HRearrange (LabelsOf yout) xo yout, HLeftUnion xi xo xixo, HRearrange (LabelsOf x) xixo x, HAllTaggedLV x, HAllTaggedLV yin, HAllTaggedLV yout) => SplitVariant x yin yout |
class ProjectVariant x y where Source
convert a variant with more fields into one with fewer (or the same) fields.
>>>
let ty = Proxy :: Proxy [Tagged "left" Int, Tagged "right" Int]
>>>
let l = mkVariant _left 1 ty
>>>
let r = mkVariant _right 2 ty
>>>
map projectVariant [l, r] :: [Maybe (Variant '[Tagged "left" Int])]
[Just V{left=1},Nothing]
is one implementation
of rearrangeVariant
= fromJust
. projectVariant
rearrangeVariant
, since the result can have the same fields with
a different order:
>>>
let yt = Proxy :: Proxy [Tagged "right" Int, Tagged "left" Int]
>>>
map projectVariant [l, r] `asTypeOf` [Just (mkVariant _left 0 yt)]
[Just V{left=1},Just V{right=2}]
projectVariant :: Variant x -> Maybe (Variant y) Source
ProjectVariant x ([] *) | |
(ProjectVariant x ys, HasField k t (Variant x) (Maybe y), HOccursNot * (Label k t) (LabelsOf ys), (~) * ty (Tagged k t y)) => ProjectVariant x ((:) * ty ys) |
class (HAllTaggedLV y, HAllTaggedLV x) => ExtendsVariant x y where Source
projectVariant . extendsVariant = Just
(when the types match up)
extendVariant
is a special case
extendsVariant :: Variant x -> Variant y Source
(HAllTaggedLV x, Unvariant ((:) * le ([] *)) e, MkVariant k l e x, (~) * le (Tagged k l e)) => ExtendsVariant ((:) * le ([] *)) x | |
(MkVariant k l e y, (~) * le (Tagged k l e), ExtendsVariant ((:) * b bs) y) => ExtendsVariant ((:) * le ((:) * b bs)) y |
class HAllTaggedLV y => ProjectExtendVariant x y where Source
projectExtendVariant = fmapextendVariant
.projectVariant
where intermediate variant is as large as possible. Used to implement
Data.HList.Labelable.projected
Note that:
>>>
let r = projectExtendVariant (mkVariant1 Label 1 :: Variant '[Tagged "x" Int])
>>>
r :: Maybe (Variant '[Tagged "x" Integer])
Nothing
projectExtendVariant :: Variant x -> Maybe (Variant y) Source
HAllTaggedLV y => ProjectExtendVariant ([] *) y | |
((~) * lv (Tagged k l v), HMemberM * lv y inY, ProjectExtendVariant' inY lv y, ProjectExtendVariant xs y) => ProjectExtendVariant ((:) * lv xs) y |
one
class (SameLength s t, SameLabels s t) => HPrism x s t a b | x s -> a, x t -> b, x s b -> t, x t a -> s where Source
Make a Prism (Variant s) (Variant t) a b
out of a Label.
See Data.HList.Labelable.hLens'
is a more overloaded version.
Few type annotations are necessary because of the restriction
that s
and t
have the same labels in the same order, and to
get "t" the "a" in "s" is replaced with "b".
(MkVariant k x b t, HasField k x (Variant s) (Maybe a), SameLength * * s t, SameLabels [*] [*] s t, H2ProjectByLabels ((:) * (Label k x) ([] *)) s si so, H2ProjectByLabels ((:) * (Label k x) ([] *)) t ti to, (~) [*] so to, HUpdateAtLabel k Variant x b s t, HUpdateAtLabel k Variant x a t s) => HPrism k x s t a b |
unvarianted :: (Unvariant' s a, Unvariant' t b, SameLabels s t, SameLength s t, Functor f) => (a -> f b) -> Variant s -> f (Variant t) Source
Lens (Variant s) (Variant t) a b
Analogue of Control.Lens.chosen :: Lens (Either a a) (Either b b) a b
unvarianted' :: (HAllEqVal ((:) * (Tagged * () b) s) b1, HAllEqVal s b1, HAllEqVal' ((:) * (Tagged * () b) s), Unvariant1 Bool b1 s b, SameLength' * * s s, SameLabels [*] [*] s s, Functor f) => (b -> f b) -> Variant s -> f (Variant s) Source
Lens' (Variant s) a
where we might have s ~ '[Tagged t1 a, Tagged t2 a]
splitVariant1' :: Variant (x : xs) -> Either x (Variant xs) Source
x ~ Tagged s t
extendVariant :: Variant l -> Variant (e : l) Source
implementation
class Unvariant v e | v -> e where Source
Convert a Variant which has all possibilities having the same type
into a value of that type. Analogous to either id id
.
See also unvariant'
class Unvariant' v e | v -> e where Source
Similar to unvariant
, except type variables in v
will be made equal to e
if possible. That allows the type
of Nothing
to be inferred as Maybe Char
.
>>>
unvariant' $ x .=. Nothing .*. mkVariant1 y 'y'
'y'
However, this difference leads to more local error messages
(Couldn't match type ‘()’ with ‘Char’
), rather than the following
with unvariant
:
Fail '("Variant", '[Tagged "left" Char, Tagged "right" ()], "must have all values equal to ", e))
unvariant' :: Variant v -> e Source
(HAllEqVal' ((:) * (Tagged * () e) v), Unvariant v e) => Unvariant' v e |
Conversions between collections
class TypeIndexed r tr | r -> tr, tr -> r where Source
Conversion between type indexed collections (TIC
and TIP
)
and the corresponding collection that has other label types (Variant
and Record
respectively)
See typeIndexed'
typeIndexed :: forall p f s t a b. (TypeIndexedCxt s t a b, Profunctor p, Functor f) => p (tr (TagR a)) (f (tr (TagR b))) -> p (r s) (f (r t)) Source
Iso (r s) (r t) (tr a) (tr b)
typeIndexed' :: (TypeIndexed r tr, TagUntagFD (RecordValuesR s) (TagR (RecordValuesR s)), HLabelSet [*] (LabelsOf s), RecordValues s, HMapAux HList TaggedFn (RecordValuesR s) s, SameLength' * * (RecordValuesR s) (RecordValuesR s), SameLength' * * s s, SameLabels [*] [*] s s, HAllTaggedLV s, Profunctor p, Coercible [*] (TagR (RecordValuesR s)) s, Functor f) => p (tr (TagR (RecordValuesR s))) (f (tr (TagR (RecordValuesR s)))) -> p (r s) (f (r s)) Source
HList and Record
HList and TIP
tipHList :: (TagUntagFD a1 l, TagUntagFD a ta, Profunctor p, Functor f) => p (HList a) (f (HList a1)) -> p (TIP ta) (f (TIP l)) Source
Iso (TIP (TagR a)) (TIP (TagR b)) (HList a) (HList b)
tipHList' :: (TagUntagFD a ta, Profunctor p, Functor f) => p (HList a) (f (HList a)) -> p (TIP ta) (f (TIP ta)) Source
Iso' (TIP (TagR s)) (HList a)
Record and RecordU
unboxed :: forall x y f p. (Profunctor p, Functor f, RecordToRecordU x, RecordUToRecord y) => (RecordU x `p` f (RecordU y)) -> Record x `p` f (Record y) Source
Iso (Record x) (Record y) (RecordU x) (RecordU y)
unboxed' :: (RecordValues x, HMapAux HList TaggedFn (RecordValuesR x) x, HList2List (RecordValuesR x) (GetElemTy x), HLengthEq1 HNat x n, HLengthEq2 HNat x n, SameLength' * * (HReplicateR * n ()) x, Profunctor p, IArray UArray (GetElemTy x), KnownNat (HNat2Nat n), Functor f) => p (RecordU x) (f (RecordU x)) -> p (Record x) (f (Record x)) Source
Iso' (Record x) (RecordU x)
Record and RecordUS
unboxedS :: (HMapUnboxF g1 u1, HMapUnboxF g u, HConcatFD g1 x1, HMapAux HList UnboxF g u, HMapAux HList BoxF u1 g1, HGroupBy * EqTagValue x1 g1, HGroupBy * EqTagValue x g, SameLength' * * g1 u1, SameLength' * * g u, SameLength' * * u1 g1, SameLength' * * u g, Profunctor p, Functor f) => p (RecordUS x) (f (RecordUS x1)) -> p (Record x) (f (Record x1)) Source
Iso (Record x) (Record y) (RecordUS x) (RecordUS y)
unboxedS' :: (HMapUnboxF g u, HConcatFD g x, HMapAux HList UnboxF g u, HMapAux HList BoxF u g, HGroupBy * EqTagValue x g, SameLength' * * g u, SameLength' * * u g, Profunctor p, Functor f) => p (RecordUS x) (f (RecordUS x)) -> p (Record x) (f (Record x)) Source
Iso' (Record x) (RecordUS x)
Record and Variant
hMaybied :: (VariantToHMaybied v1 x, VariantToHMaybied v r, HFoldr HMaybiedToVariantFs [Variant ([] *)] x [Variant v1], HMapAux HList (HFmap HCastF) x r, SameLength' * * x r, SameLength' * * r x, Choice p, Applicative f) => p (Variant v1) (f (Variant v)) -> p (Record x) (f (Record r)) Source
Prism (Record tma) (Record tmb) (Variant ta) (Variant tb)
see hMaybied'
hMaybied' :: (VariantToHMaybied v x, HFoldr HMaybiedToVariantFs [Variant ([] *)] x [Variant v], HMapAux HList (HFmap HCastF) x x, SameLength' * * x x, Choice p, Applicative f) => p (Variant v) (f (Variant v)) -> p (Record x) (f (Record x)) Source
Prism' (Record tma) (Variant ta)
where tma
and tmb
are lists like
tma ~ '[Tagged x (Maybe a), Tagged y (Maybe b)] ta ~ '[Tagged x a , Tagged y b ]
If one element of the record is Just, the Variant will contain that element. Otherwise, the prism fails.
Note
The types work out to define a prism:
l =prism'
variantToHMaybied
(listToMaybe
.hMaybiedToVariants
)
but the law: s^?l ≡ Just a ==> l # a ≡ s
is not followed,
because we could have:
s, s2 :: Record '[Tagged "x" (Maybe Int), Tagged "y" (Maybe Char)] s = hBuild (Just 1) (Just '2') s2 = hBuild (Just 1) Nothing v :: Variant '[Tagged "x" Int, Tagged "y" Char] v = mkVariant (Label :: Label "x") 1 Proxy
So that s^?l == Just v
. But l#v == s2 /= s
, while the law
requires l#v == s
. hMaybied avoids this problem by only
producing a value when there is only one present.
Newtype wrappers
hListRecord
hListRecord'
are exported under Data.HList.Record
ticVariant :: (Profunctor p, Functor f) => p (Variant t) (f (Variant l)) -> p (TIC t) (f (TIC l)) Source
Iso (TIC s) (TIC t) (Variant s) (Variant t)
typeIndexed
may be more appropriate
ticVariant' :: (Profunctor p, Functor f) => p (Variant t) (f (Variant t)) -> p (TIC t) (f (TIC t)) Source
Iso' (TIC s) (Variant s)
tipRecord :: (Profunctor p, Functor f) => p (Record r) (f (Record l)) -> p (TIP r) (f (TIP l)) Source
Iso (TIP s) (TIP t) (Record s) (Record t)
typeIndexed
may be more appropriate
tipRecord' :: (Profunctor p, Functor f) => p (Record r) (f (Record r)) -> p (TIP r) (f (TIP r)) Source
Iso' (TIP (TagR s)) (Record a)
implementation
class VariantToHMaybied v r | v -> r, r -> v where Source
variantToHMaybied :: Variant v -> Record r Source
VariantToHMaybied ([] *) ([] *) | |
(VariantToHMaybied v r, HReplicateF nr ConstTaggedNothing () r, (~) * tx (Tagged k t x), (~) * tmx (Tagged k t (Maybe x))) => VariantToHMaybied ((:) * tx v) ((:) * tmx r) |
hMaybiedToVariants :: (HFoldr HMaybiedToVariantFs [Variant []] r [Variant v], VariantToHMaybied v r) => Record r -> [Variant v] Source
Every element of the record that is Just becomes one element
in the resulting list. See hMaybied'
example types that r
and v
can take.
Data.HList.Keyword
the "public" parts. More examples are in the module documentation.
class Kw fn arg_def r where Source
kw
takes a HList
whose first element is a function, and the rest
of the elements are default values.
A useful trick is to have a final argument ()
which is not
eaten up by a label (A only takes 1 argument). That way when you supply
the () it knows there are no more arguments (?).
>>>
data A = A
>>>
instance IsKeyFN (A -> a -> b) True
>>>
let f A a () = a + 1
>>>
let f' = f .*. A .*. 1 .*. HNil
>>>
kw f' A 0 ()
1
>>>
kw f' ()
2
recToKW :: forall a b. (HMapCxt HList TaggedToKW a b, HConcat b) => Record a -> HList (HConcatR b) Source
convert a Record
into a list that can supply
default arguments for kw
A bit of setup:
>>>
:set -XQuasiQuotes
>>>
import Data.HList.RecordPuns
>>>
let f (_ :: Label "a") a (_ :: Label "b") b () = a `div` b
>>>
let a = 2; b = 1; f' = f .*. recToKW [pun| a b |]
>>>
kw f' ()
2
>>>
kw f' (Label :: Label "a") 10 ()
10
class IsKeyFN t flag | t -> flag Source
All our keywords must be registered
(~) Bool False flag => IsKeyFN t flag | overlapping/fallback case |
IsKeyFN (Label Symbol s -> a -> b) True | labels that impose no restriction on the type of the (single) argument which follows
|
(~) * r (c -> b) => IsKeyFN (K k s c -> r) True | The purpose of this instance is to be able to use the same Symbol
(type-level string) at different types. If they are supposed to be the same,
then use
therefore the following options works:
But you cannot leave off all |
(~) * r (c -> b) => IsKeyFN (K k s c -> r) True | The purpose of this instance is to be able to use the same Symbol
(type-level string) at different types. If they are supposed to be the same,
then use
therefore the following options works:
But you cannot leave off all |
data ErrReqdArgNotFound x Source
data ErrUnexpectedKW x Source
Labels
there are three options for now. However, there are a couple different styles for the first option here:
GHC supports type-level strings (Symbol
), and these can be
labels. You can refer to these strings using an unwieldy syntax described
below. For example if you want to store a value 5
in a record rec
with a field called "x"
, and then get it out again:
let rec = (Label
:: Label "x") .=.
5 .*.
emptyRecord
rec .!.
(Label :: Label "x")
To avoid that pain, you can have a definition x = Label :: Label "x"
.
and just use x
instead of repeating Label :: Label "x"
so that
a lookup becomes:
rec .!. x
makeLabels6
automates definitions like x = Label :: Label "x"
.
Instances from Data.HList.Label6
>>>
:set -XDataKinds
>>>
(Label :: Label "x") .=. (5::Int) .*. emptyRecord
Record{x=5}
>>>
let x = Label :: Label "x"
>>>
let r = x .=. (5::Int) .*. emptyRecord
>>>
r .!. x
5
module Data.HList.Labelable
Rather than having the x = Label :: Label "x"
, the labels
generated by makeLabelable
also double as lenses for Control.Lens.
Here is an example of how much better that is:
>>>
:set -XNoMonomorphismRestriction -XDataKinds -XPolyKinds
>>>
import Control.Lens
>>>
import Data.HList.Labelable
>>>
let x = hLens' (Label :: Label "x")
>>>
let y = hLens' (Label :: Label "y")
The Label6 method:
>>>
let r = (Label :: Label "x") .=. "5" .*. emptyRecord
The Labelable way:
>>>
let r2 = x .==. "5" .*. emptyRecord
>>>
r ^. x
"5"
>>>
r2 ^. x
"5"
>>>
r & x .~ ()
Record{x=()}
When a field is missing, the error names that field:
>>>
:t r^.y
... ...No instance for (Fail (FieldNotFound "y")) ...
namespaced labels
module Data.HList.Label3
labels as any instance of Typeable
template haskell
module Data.HList.MakeLabels
Data.HList.Data
This modules provide useful instances. A useful application can be
found in examples/cmdargs.hs
Overlapping instances are restricted to here
module Data.HList.TypeEqO
Internals
internals exported for type signature purposes
class HAllTaggedEq l Source
HAllTaggedEq ([] *) | |
(HAllTaggedEq l, (~) * tee (Tagged k e e')) => HAllTaggedEq ((:) * tee l) |