HList-0.4.0.0: Heterogeneous lists

Copyright(C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
Safe HaskellNone
LanguageHaskell2010

Data.HList.CommonMain

Contents

Description

The HList library

This module re-exports everything needed to use HList.

Synopsis

Faking dependent types in Haskell

Functions for all collections

Array-like access to HLists

Result-type-driven operations

Type-indexed operations

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.

HList

A subset of Data.HList.HList is re-exported.

A subset of Data.HList.HSort

hSort :: HSort x y => HList x -> HList y Source

type HSort x y = HSortBy HLeFn x y Source

class (SameLength a b, HEqByFn le) => HSortBy le a b | le a -> b where Source

quick sort with a special case for sorted lists

Methods

hSortBy :: Proxy le -> HList a -> HList b Source

Instances

(SameLength * * a b, HIsAscList k le a ok, HSortBy1 Bool k ok le a b) => HSortBy k le a b 

data HLeFn Source

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

Instances

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

>>> let b1 = Proxy :: HEqBy HLeFn "x" "y" b => Proxy b
>>> :t b1
b1 :: Proxy 'True
>>> let b2 = Proxy :: HEqBy HLeFn "x" "x" b => Proxy b
>>> :t b2
b2 :: Proxy 'True
>>> let b3 = Proxy :: HEqBy HLeFn "y" "x" b => Proxy b
>>> :t b3
b3 :: Proxy 'False
(~) 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.

data HDown a Source

analogous to Down

Instances

HEqBy k1 k f y x b => HEqBy * k (HDown k f) x y b 
HEqByFn k a => HEqByFn * (HDown k a) 

class HSetBy (HNeq HLeFn) ps => HSet ps Source

Instances

HSetBy * (HNeq * HLeFn) ps => HSet ps 

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

Instances

(HSortBy k lt ps ps', HAscList k lt ps') => HSetBy k lt ps 

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

Instances

HIsSetBy * (HNeq * HLeFn) ps b => HIsSet ps b 

class HEqByFn lt => HIsSetBy lt ps b | lt ps -> b Source

Instances

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

Instances

HAscList0 k le ps ps => HAscList k le ps 

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)

Instances

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

Methods

hUncurry' :: Proxy n -> f -> HList xs -> r Source

hCurry' :: Proxy n -> (HList xs -> r) -> f Source

Instances

HCurry' HZero b ([] *) b 
HCurry' n b xs r => HCurry' (HSucc n) (x -> b) ((:) * x xs) r 

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.

hUncurry :: (HCurry' n f xs r, ArityFwd f n, ArityRev f n) => f -> HList xs -> r Source

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

data TIP l Source

TIPs are like Record, except element "i" of the list "l" has type Tagged e_i e_i

Instances

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

((~) * 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.orgtracghcticket/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 x HCons hTagSelf xs
    hUntagSelf (HCons (Tagged x) xs) = x HCons 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 () ()]

Methods

hTagSelf :: HList a -> HList ta Source

hUntagSelf :: HList ta -> HList a Source

Instances

TagUntagFD ([] *) ([] *) 
(TagUntagFD xs ys, (~) * txx (Tagged * x x)) => TagUntagFD ((:) * x xs) ((:) * txx ys) 

type family TagR a :: [*] Source

Instances

type TagR ([] *) = [] * 
type TagR ((:) * x xs) = (:) * (Tagged * x x) (TagR xs) 

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

Methods

ttip :: op -> TIP db -> TIP db Source

Instances

(HMember * (Tagged * op op) db b, Arity op n, TransTIP1 b n op db) => TransTIP op db 

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.

Methods

ttipM :: op -> TIP db -> m (TIP db) Source

Instances

(Monad m, HMember * (Tagged * op op) db b, Arity (m' op) n, TransTIPM1 b n m (m' op) db) => TransTIPM m (m' op) db 

TIC

Public interface of Data.HList.TIC

data TIC l Source

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.

Instances

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

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, HNat2Integral n, HAllTaggedLV l) => 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

mkTIC' Source

Arguments

:: (HTypeIndexed l, MkVariant i i l) 
=> i 
-> proxy l

the ordering of types in the l :: [*] matters. This argument is intended to fix the ordering it can be a Record, Variant, TIP, Proxy

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

data Variant vs Source

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)

Instances

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 Prism (Variant s) (Variant t) a b

(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 (unsafeEmptyVariant). Enum can produce values, so it is better that fromEnum 0 :: Variant '[] fails with No instance for Enum (Variant '[]) than producing an invalid variant.

(Enum x, Bounded x, Enum (Variant ((:) * y z))) => Enum (Variant ((:) * (Tagged k s x) ((:) * y z)))
>>> let t = minBound :: Variant '[Tagged "x" Bool, Tagged "y" Bool]
>>> [t .. maxBound]
[V{x=False},V{x=True},V{y=False},V{y=True}]
Odd behavior
There are some arguments that this instance should not exist.

The last type in the Variant does not need to be Bounded. This means that enumFrom behaves a bit unexpectedly:

>>> [False .. ]
[False,True]
>>> [t .. ]
[V{x=False},V{x=True},V{y=False},V{y=True},V{y=*** Exception: Prelude.Enum.Bool.toEnum: bad argument

This is a "feature" because it allows an Enum (Variant '[Tagged "a" Bool, Tagged "n" Integer])

Another difficult choice is that the lower bound is fromEnum 0 rather than minBound:

>>> take 5 [ minBound :: Variant '[Tagged "b" Bool, Tagged "i" Int] .. ]
[V{b=False},V{b=True},V{i=0},V{i=1},V{i=2}]
(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) 

mkVariant Source

Arguments

:: MkVariant x v vs 
=> Label x

the tag

-> v

value to be stored

-> proxy vs

a helper to fix the ordering and types of the potential values that this variant contains. Typically this will be a Proxy, Record or another Variant

-> Variant vs 

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

newtype HMapV f Source

Apply a function to all possible elements of the variant

Constructors

HMapV f 

Instances

((~) * vx (Variant x), (~) * vy (Variant y), HMapAux Variant (HFmap f) x y, SameLength * * x y) => ApplyAB (HMapV f) vx vy

apply a function to all values that could be in the variant.

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

Methods

zipVariant :: Variant x -> Variant y -> Maybe (Variant xy) Source

Instances

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.

Methods

zipVR_ :: Record fs -> Variant v -> Variant v' Source

zipVR is probably a better choice in most situations, since it requires that fs has one function for every element of v

Instances

ZipVR fs ([] *) ([] *) 
((~) * lv (Tagged k l v), (~) * lv' (Tagged k l v'), HMemberM * (Label k l) (LabelsOf fs) b, HasFieldM k l (Record fs) f, (~) * (DemoteMaybe (v -> v) f) (v -> v'), MkVariant k l v' ((:) * lv' rs), ZipVR fs vs rs) => ZipVR fs ((:) * lv vs) ((:) * lv' rs) 

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

Methods

splitVariant :: Variant x -> Either (Variant yin) (Variant yout) Source

Instances

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

rearrangeVariant = fromJust . projectVariant is one implementation of 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}]

Instances

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

Instances

(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 = fmap extendVariant . 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

Instances

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

Methods

hPrism :: (Choice p, Applicative f) => Label x -> p a (f b) -> p (Variant s) (f (Variant t)) Source

Instances

(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

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'

Methods

unvariant :: Variant v -> e Source

Instances

(Unvariant1 Bool b v e, HAllEqVal v b, HAllEqVal ((:) * (Tagged * () e) v) b) => Unvariant v e 

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))

Methods

unvariant' :: Variant v -> e Source

Instances

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

Methods

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

Iso' (Variant s) (TIC a)
Iso' (Record s) (TIP a)

where s has a type like '[Tagged "x" Int], and a has a type like '[Tagged Int Int].

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)

Newtype wrappers

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)

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.

implementation

class VariantToHMaybied v r | v -> r, r -> v where Source

Instances

VariantToHMaybied ([] *) ([] *) 
(VariantToHMaybied v r, HReplicateF nr ConstTaggedNothing () r, (~) * tx (Tagged k t x), (~) * tmx (Tagged k t (Maybe x))) => VariantToHMaybied ((:) * tx v) ((:) * tmx r) 

data HMaybiedToVariantFs Source

Instances

((~) * x (Tagged k t (Maybe e), [Variant v]), (~) * y [Variant ((:) * (Tagged k t e) v)], MkVariant k t e ((:) * (Tagged k t e) v)) => ApplyAB HMaybiedToVariantFs x y 

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

Methods

kw :: HList (fn : arg_def) -> r Source

Instances

(KW' Bool rflag fn akws arg_def r, (~) * akws (Arg [*] kws ([] *)), ReflectFK' * [*] flag fn kws, IsKeyFN r rflag, IsKeyFN fn flag) => Kw fn arg_def r 

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

Instances

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

>>> let testF (_ :: Label "a") (a :: Int) () = a+1
>>> kw (hBuild testF) (Label :: Label "a") 5 ()
6
(~) * 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 Label instead of K

>>> let kA = K :: forall t. K "a" t
>>> let testF (K :: K "a" Int) a1 (K :: K "a" Integer) a2 () = a1-fromIntegral a2

therefore the following options works:

>>> kw (hBuild testF) kA (5 :: Int) kA (3 :: Integer) ()
2
>>> kw (hBuild testF) (K :: K "a" Integer) 3 (K :: K "a" Int) 5 ()
2

But you cannot leave off all Int or Integer annotations.

data K s c Source

Instances

(~) * 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 Label instead of K

>>> let kA = K :: forall t. K "a" t
>>> let testF (K :: K "a" Int) a1 (K :: K "a" Integer) a2 () = a1-fromIntegral a2

therefore the following options works:

>>> kw (hBuild testF) kA (5 :: Int) kA (3 :: Integer) ()
2
>>> kw (hBuild testF) (K :: K "a" Integer) 3 (K :: K "a" Int) 5 ()
2

But you cannot leave off all Int or Integer annotations.

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

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

labels as any instance of Typeable

template haskell

Data.HList.Data

This modules provide useful instances. A useful application can be found in examples/cmdargs.hs

Overlapping instances are restricted to here

Internals

internals exported for type signature purposes

class HAllTaggedEq l Source

Instances

HAllTaggedEq ([] *) 
(HAllTaggedEq l, (~) * tee (Tagged k e e')) => HAllTaggedEq ((:) * tee l)