HList-0.4.1.0: Heterogeneous lists

Data.HList.HList

Description

The HList library

(C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke

Basic declarations for typeful heterogeneous lists.

Excuse the unstructured haddocks: while there are many declarations here some are alternative implementations should be grouped, and the definitions here are analgous to many list functions in the Prelude.

Synopsis

# Heterogeneous type sequences

There are three sensible ways to define HLists:

```data HList (l::[*]) where
HNil  :: HList '[]
HCons :: e -> HList l -> HList (e ': l)
```

This ensures that sequences can only be formed with Nil and Cons. The argument to HList is a promoted lists (kind `[*]`), which has a more attractive syntax.

Earlier versions of HList used an algebraic data type:

```data HCons a b = HCons a b
data HNil = HNil
```

• values with types like `HCons Int Double` to be created, which are nonsense to the functions in HList
• some recursive functions do not need a class with the GADT. For example:
```   hInit :: HListGADT (x ': xs) -> HListGADT (HInit (x ': xs))
hInit (HCons x xs@(HCons _ _)) = HCons x (hInit xs)
hInit (HCons _ HNil) = HNil

type family HInit (xs :: [k]) :: [k]
```

but without the GADT, `hInit` is written as in a class, which complicates inferred types

• lazy pattern matches are allowed, so lazy pattern matching on a value `undefined :: HList [a,b,c]` can create the spine of the list. `hProxies` avoids the use of `undefined`, but a slightly more complicated class context has to be written or inferred.
• type inference is better if you want to directly pattern match see stackoverflow post here
• better pattern exhaustiveness checking (as of ghc-7.8)
• standalone deriving works
• Data.Coerce.coerce works because the parameters have role representational, not nominal as they are for the GADT and data family. Probably the GADT/type family actually do have a representational role: http://stackoverflow.com/questions/24222552/does-this-gadt-actually-have-type-role-representational

The data family version (currently used) gives the same type constructor `HList :: [*] -> *` as the GADT, while pattern matching behaves like the algebraic data type. Furthermore, nonsense values like `HCons 1 2 :: HCons Int Int` cannot be written with the data family.

A variation on the data family version is

```data instance HList '[] = HNil
newtype instance HList (x ': xs) = HCons1 (x, HList xs)
pattern HCons x xs = HCons1 (x, xs)```

This allows HList to have a nominal role, but on the other hand the PatternSynonym is not supported with ghc-7.6 and exhaustiveness checking is not as good (warnings for _ being unmatched)

data family HList l Source

Instances

 (SameLengths * ((:) [*] x ((:) [*] y ((:) [*] xy ([] [*])))), HZipList x y xy) => HZip HList x y xy (SameLengths * ((:) [*] x ((:) [*] y ((:) [*] xy ([] [*])))), HZipList x y xy) => HUnzip HList x y xy (HDeleteAtHNat n l, HType2HNat * e l n, (~) [*] l' (HDeleteAtHNatR n l)) => HDeleteAtLabel * HList e l l' should this instead delete the first element of that type? (HEq * e1 e b, HDeleteManyCase * b e1 e l l1) => HDeleteMany * e1 (HList ((:) * e l)) (HList l1) HDeleteMany k e (HList ([] *)) (HList ([] *)) HMapAux HList f ([] *) ([] *) (HSpanEqBy k f a as fst snd, HGroupBy k f snd gs) => HGroupBy k f ((:) * a as) ((:) * (HList ((:) * a fst)) gs) (ApplyAB f e e', HMapAux HList f l l', SameLength * * l l') => HMapAux HList f ((:) * e l) ((:) * e' l') (HOccurs e l, HProject l (HList l')) => HProject l (HList ((:) * e l')) (HOccurrence e ((:) * x y) l', HOccurs' e l') => HOccurs e (HList ((:) * x y)) HExtend e (HList l) HReverse l l' => HBuild' l (HList l') HInits1 a b => HInits a ((:) * (HList ([] *)) b) (Bounded x, Bounded (HList xs)) => Bounded (HList ((:) * x xs)) Bounded (HList ([] *)) (Eq x, Eq (HList xs)) => Eq (HList ((:) * x xs)) Eq (HList ([] *)) (Data x, Data (HList xs), TypeablePolyK [*] ((:) * x xs), Typeable * (HList ((:) * x xs))) => Data (HList ((:) * x xs)) Typeable * (HList ([] *)) => Data (HList ([] *)) (Ord x, Ord (HList xs)) => Ord (HList ((:) * x xs)) Ord (HList ([] *)) (HProxies l, Read e, HSequence ReadP ((:) * (ReadP e) readP_l) ((:) * e l), HMapCxt HList ReadElement (AddProxy [*] l) readP_l) => Read (HList ((:) * e l)) Read (HList ([] *)) (Show e, Show (HList l)) => Show (HList ((:) * e l)) Show (HList ([] *)) (Ix x, Ix (HList xs)) => Ix (HList ((:) * x xs)) Ix (HList ([] *)) (HProxies a, HMapCxt HList ConstMempty (AddProxy [*] a) a, HZip HList a a aa, HMapCxt HList UncurryMappend aa a) => Monoid (HList a) Analogous to the Monoid instance for tuples````>>> ````import Data.Monoid ````>>> ````mempty :: HList '[(), All, [Int]] ```H[(),All {getAll = True},[]] ```````>>> ````mappend (hBuild "a") (hBuild "b") :: HList '[String] ```H["ab"] ``` (TypeRepsList (HList xs), Typeable * x) => TypeRepsList (HList ((:) * x xs)) TypeRepsList (HList ([] *)) HProject (HList l) (HList ([] *)) HAppendList l1 l2 => HAppend (HList l1) (HList l2) ApplyAB f e e' => ApplyAB (MapCar f) (e, HList l) (HList ((:) * e' l)) HInits1 ([] *) ((:) * (HList ([] *)) ([] *)) HTails ([] *) ((:) * (HList ([] *)) ([] *)) Typeable ([*] -> *) HList Apply (FHUProj sel ns) (HList l, Proxy HNat (HSucc n)) => Apply (Proxy Bool False, FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) Apply (Proxy Bool True, FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) ((~) * ch (Proxy Bool (HBoolEQ sel (KMember n ns))), Apply (ch, FHUProj sel ns) (HList ((:) * e l), Proxy HNat n)) => Apply (FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) Apply (FHUProj sel ns) (HList ([] *), n) (HConcatFD as bs, HAppendFD a bs cs) => HConcatFD ((:) * (HList a) as) cs (HInits1 xs ys, HMapCxt HList (FHCons2 x) ys ys', (~) [*] (HMapCons x ys) ys', (~) [*] (HMapTail ys') ys) => HInits1 ((:) * x xs) ((:) * (HList ((:) * x ([] *))) ys') HTails xs ys => HTails ((:) * x xs) ((:) * (HList ((:) * x xs)) ys) HMapUnboxF xs us => HMapUnboxF ((:) * (HList x) xs) ((:) * (RecordU x) us) ((~) * (HList ((:) * x y)) z, HZip3 xs ys zs) => HZip3 ((:) * x xs) ((:) * (HList y) ys) ((:) * z zs) type HExtendR e (HList l) = HList ((:) * e l) type HAppendR * (HList l1) (HList l2) = HList (HAppendListR * l1 l2) type HMapCons x ((:) * (HList a) b) = (:) * (HList ((:) * x a)) (HMapCons x b) type UnHList (HList a) = a data HList ([] *) = HNil type ApplyR (Proxy Bool False, FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) = ApplyR (FHUProj sel ns) (HList l, Proxy HNat (HSucc n)) type ApplyR (Proxy Bool True, FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) = HJust (e, (HList l, Proxy HNat (HSucc n))) type ApplyR (FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) = ApplyR (Proxy Bool (HBoolEQ sel (KMember n ns)), FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) type ApplyR (FHUProj sel ns) (HList ([] *), n) = HNothing type HMapTail ((:) * (HList ((:) * a as)) bs) = (:) * (HList as) (HMapTail bs) data HList ((:) * x xs) = x `HCons` (HList xs)

class HProxiesFD xs pxs | pxs -> xs, xs -> pxs where Source

creates a HList of Proxies

Methods

hProxies :: HList pxs Source

Instances

 HProxiesFD ([] *) ([] *) HProxiesFD xs pxs => HProxiesFD ((:) * x xs) ((:) * (Proxy * x) pxs)

type family AddProxy xs :: k Source

Add `Proxy` to a type

````>>> ````let x = undefined :: HList (AddProxy [Char,Int])
````>>> ````:t x
```x :: HList '[Proxy Char, Proxy Int]
```

Instances

 type AddProxy * x = Proxy * x type AddProxy [k] ([] k) = [] k type AddProxy [k] ((:) k x xs) = (:) k (AddProxy k x) (AddProxy [k] xs)

type family DropProxy xs :: k Source

inverse of `AddProxy`

Instances

 type DropProxy * (Proxy * x) = x type DropProxy [k] ([] k) = [] k type DropProxy [k] ((:) k x xs) = (:) k (DropProxy k x) (DropProxy [k] xs)

Constructors

Instances

# Basic list functions

hHead :: HList (e : l) -> e Source

`head`

hTail :: HList (e : l) -> HList l Source

`tail`

hLast :: HRevApp l1 ([] *) ((:) * e l) => HList l1 -> e Source

`last`

class HInit xs where Source

Associated Types

type HInitR xs :: [*] Source

Methods

hInit :: HList xs -> HList (HInitR xs) Source

Instances

 HInit ((:) * b c) => HInit ((:) * a ((:) * b c)) HInit ((:) * x ([] *))

type family HLength x :: HNat Source

Length, but see `HLengthEq` instead

Instances

 type HLength k ([] k) = HZero type HLength k ((:) k x xs) = HSucc (HLength k xs)

## Append

type family HAppendListR l1 l2 :: [k] Source

Instances

 type HAppendListR k ([] k) l = l type HAppendListR k ((:) k e l) l' = (:) k e (HAppendListR k l l')

class HAppendList l1 l2 where Source

Methods

hAppendList :: HList l1 -> HList l2 -> HList (HAppendListR l1 l2) Source

the same as `hAppend`

Instances

 HAppendList ([] *) l2 HAppendList l l' => HAppendList ((:) * x l) l'

## Alternative append

append' :: [a] -> [a] -> [a] Source

`hAppend'` below is implemented using the same idea

hAppend' :: HFoldr FHCons v l r => HList l -> v -> r Source

Alternative implementation of `hAppend`. Demonstrates `HFoldr`

data FHCons Source

Constructors

 FHCons

Instances

 ((~) * x (e, HList l), (~) * y (HList ((:) * e l))) => ApplyAB FHCons x y

## Historical append

The original HList code is included below. In both cases we had to program the algorithm twice, at the term and the type levels.

`The class HAppend`
```class HAppend l l' l'' | l l' -> l''
where
hAppend :: l -> l' -> l''
```
`The instance following the normal append`
```instance HList l => HAppend HNil l l
where
hAppend HNil l = l

instance (HList l, HAppend l l' l'')
=> HAppend (HCons x l) l' (HCons x l'')
where
hAppend (HCons x l) l' = HCons x (hAppend l l')```

# Reversing HLists

type family HRevAppR l1 l2 :: [k] Source

Instances

 type HRevAppR k ([] k) l = l type HRevAppR k ((:) k e l) l' = HRevAppR k l ((:) k e l')

class HRevApp l1 l2 l3 | l1 l2 -> l3 where Source

Methods

hRevApp :: HList l1 -> HList l2 -> HList l3 Source

Instances

 HRevApp ([] *) l2 l2 HRevApp l ((:) * x l') z => HRevApp ((:) * x l) l' z

class HReverse xs sx | xs -> sx, sx -> xs where Source

Methods

hReverse :: HList xs -> HList sx Source

Instances

 (HRevApp xs ([] *) sx, HRevApp sx ([] *) xs) => HReverse xs sx

hReverse_ :: HRevApp l1 ([] *) l3 => HList l1 -> HList l3 Source

a version of `hReverse` that does not allow the type information to flow backwards

# A nicer notation for lists

hEnd :: HList l -> HList l Source

Note:

`x :: HList a`
means: `forall a. x :: HList a`
`hEnd x`
means: `exists a. x :: HList a`

List termination

hBuild :: HBuild' [] r => r Source

Building lists

class HBuild' l r where Source

Methods

hBuild' :: HList l -> r Source

Instances

 HReverse l l' => HBuild' l (HList l') (HReverse l lRev, HMapTaggedFn lRev l') => HBuild' l (Record l') This instance allows creating Record with`hBuild 3 `a` :: Record '[Tagged "x" Int, Tagged "y" Char]` HBuild' ((:) * a l) r => HBuild' l (a -> r) ((~) [*] (HRevAppR * l ([] *)) lRev, (~) * (HExtendRs * lRev (Proxy [*] ([] *))) (Proxy k l1), (~) k l' l1) => HBuild' l (Proxy k l') see `hEndP`

## examples

The classes above allow the third (shortest) way to make a list (containing a,b,c) in this case

```list = a `HCons` b `HCons` c `HCons` HNil
list = a .*. b .*. c .*. HNil
list = hEnd \$ hBuild a b c```
````>>> ````let x = hBuild True in hEnd x
```H[True]
```
````>>> ````let x = hBuild True 'a' in hEnd x
```H[True,'a']
```
````>>> ````let x = hBuild True 'a' "ok" in hEnd x
```H[True,'a',"ok"]
```

hBuild can also produce a Record, such that

`hBuild x y ^. from unlabeled`

can also be produced using

````hEndR` \$ hBuild x y
```

### historical

the show instance has since changed, but these uses of 'hBuild'/'hEnd' still work

```HList> let x = hBuild True in hEnd x
HCons True HNil```
```HList> let x = hBuild True 'a' in hEnd x
HCons True (HCons 'a' HNil)```
```HList> let x = hBuild True 'a' "ok" in hEnd x
HCons True (HCons 'a' (HCons "ok" HNil))```
```HList> hEnd (hBuild (Key 42) (Name "Angus") Cow (Price 75.5))
HCons (Key 42) (HCons (Name "Angus") (HCons Cow (HCons (Price 75.5) HNil)))```
```HList> hEnd (hBuild (Key 42) (Name "Angus") Cow (Price 75.5)) == angus
True```

# folds

## foldr

Consume a heterogenous list.

class HFoldr f v l r where Source

Methods

hFoldr :: f -> v -> HList l -> r Source

Instances

 (~) * v v' => HFoldr f v ([] *) v' (ApplyAB f (e, r) r', HFoldr f v l r) => HFoldr f v ((:) * e l) r' uses `ApplyAB` not `Apply`

class HScanr f z ls rs where Source

Methods

hScanr :: f -> z -> HList ls -> HList rs Source

Instances

 (~) [*] lz ((:) * z ([] *)) => HScanr f z ([] *) lz (ApplyAB f (x, r) s, HScanr f z xs ((:) * r rs), (~) [*] srrs ((:) * s ((:) * r rs))) => HScanr f z ((:) * x xs) srrs

class HFoldr1 f l r where Source

Methods

hFoldr1 :: f -> HList l -> r Source

Instances

 (ApplyAB f (e, r) r', HFoldr1 f ((:) * e' l) r) => HFoldr1 f ((:) * e ((:) * e' l)) r' uses `ApplyAB` not `Apply` (~) * v v' => HFoldr1 f ((:) * v ([] *)) v'

## foldl

class HFoldl f z xs r where Source

like `foldl`

````>>> ````hFoldl (uncurry \$ flip (:)) [] (1 `HCons` 2 `HCons` HNil)
```[2,1]
```

Methods

hFoldl :: f -> z -> HList xs -> r Source

Instances

 (~) * z z' => HFoldl f z ([] *) z' ((~) * zx (z, x), ApplyAB f zx z', HFoldl f z' xs r) => HFoldl f z ((:) * x xs) r

# unfolds

## unfold

Produce a heterogenous list. Uses the more limited `Apply` instead of `App` since that's all that is needed for uses of this function downstream. Those could in principle be re-written.

hUnfold :: (HUnfoldFD f (ApplyR f a) z, Apply f a) => f -> a -> HList z Source

type HUnfold p s = HUnfoldR p (ApplyR p s) Source

type family HUnfoldR p res :: [*] Source

Instances

 type HUnfoldR p HNothing = [] * type HUnfoldR p (HJust (e, s)) = (:) * e (HUnfoldR p (ApplyR p s))

type HUnfold' p res = HUnfoldFD p (ApplyR p res) (HUnfold p res) Source

class HUnfoldFD p res z | p res -> z where Source

Methods

hUnfold' :: p -> res -> HList z Source

Instances

 HUnfoldFD p HNothing ([] *) (Apply p s, HUnfoldFD p (ApplyR p s) z) => HUnfoldFD p (HJust (e, s)) ((:) * e z)

## replicate

class HLengthEq es n => HReplicateFD n e es | n e -> es, es -> n where Source

Sometimes the result type can fix the type of the first argument:

````>>> ````hReplicate Proxy () :: HList '[ (), (), () ]
```H[(),(),()]
```

However, with HReplicate all elements must have the same type, so it may be easier to use `HList2List`:

````>>> ````list2HList (repeat 3) :: Maybe (HList [Int, Int, Int])
```Just H[3,3,3]
```

Methods

hReplicate :: Proxy n -> e -> HList es Source

Instances

 HReplicateFD HZero e ([] *) (HReplicateFD n e es, (~) * e e') => HReplicateFD (HSucc n) e ((:) * e' es)

type family HReplicateR n e :: [k] Source

would be associated with `HReplicate` except we want it to work with `e` of any kind, not just `*` that you can put into a HList. An "inverse" of `HLength`

Instances

 type HReplicateR k HZero e = [] k type HReplicateR k (HSucc n) e = (:) k e (HReplicateR k n e)

class HLengthEq r n => HReplicateF n f z r | r -> n where Source

HReplicate produces lists that can be converted to ordinary lists

````>>> ````let two = hSucc (hSucc hZero)
````>>> ````let f = Fun' fromInteger :: Fun' Num Integer
``````
````>>> ````:t applyAB f
```applyAB f :: Num b => Integer -> b
```
````>>> ````hReplicateF two f 3
```H[3,3]
```
````>>> ````hReplicateF Proxy f 3 :: HList [Int, Double, Integer]
```H[3,3.0,3]
```

Methods

hReplicateF :: HLengthEq r n => Proxy n -> f -> z -> HList r Source

Instances

 HReplicateF HZero f z ([] *) (ApplyAB f z fz, HReplicateF n f z r') => HReplicateF (HSucc n) f z ((:) * fz r')

## iterate

class HLengthEq r n => HIterate n f z r where Source

This function behaves like `iterate`, with an extra argument to help figure out the result length

````>>> ````let three = hSucc (hSucc (hSucc hZero))
````>>> ````let f = Fun Just :: Fun '() Maybe
``````
````>>> ````:t applyAB f
```applyAB f :: a -> Maybe a
```

f is applied to different types:

````>>> ````hIterate three f ()
```H[(),Just (),Just (Just ())]
```

It is also possible to specify the length later on, as done with Prelude.`iterate`

````>>> ````let take3 x | _ <- hLength x `asTypeOf` three = x
````>>> ````take3 \$ hIterate Proxy f ()
```H[(),Just (),Just (Just ())]
```

Methods

hIterate :: HLengthEq r n => Proxy n -> f -> z -> HList r Source

Instances

 HIterate HZero f z ([] *) (ApplyAB f z z', HIterate n f z' r', (~) * z z_) => HIterate (HSucc n) f z ((:) * z_ r')

# concat

type HConcat xs = HConcatFD xs (HConcatR xs) Source

Like `concat` but for HLists of HLists.

Works in ghci... puzzling as what is different in doctest (it isn't `-XExtendedDefaultRules`)

````>>> ````let a = hEnd \$ hBuild 1 2 3
````>>> ````let b = hEnd \$ hBuild 'a' "abc"
````>>> ````hConcat \$ hBuild a b
```H[1, 2, 3, 'a', "abc"]
```

type family HConcatR a :: [*] Source

Instances

 type HConcatR ([] *) = [] * type HConcatR ((:) * x xs) = HAppendListR * (UnHList x) (HConcatR xs)

type family UnHList a :: [*] Source

Instances

 type UnHList (HList a) = a

class HConcatFD xxs xs | xxs -> xs where Source

Methods

hConcatFD :: HList xxs -> HList xs Source

Instances

 HConcatFD ([] *) ([] *) (HConcatFD as bs, HAppendFD a bs cs) => HConcatFD ((:) * (HList a) as) cs

class HAppendFD a b ab | a b -> ab where Source

Methods

hAppendFD :: HList a -> HList b -> HList ab Source

Instances

 HAppendFD ([] *) b b HAppendFD as bs cs => HAppendFD ((:) * a as) bs ((:) * a cs)

# traversing HLists

## producing HList

### map

It could be implemented with `hFoldr`, as we show further below

newtype HMap f Source

hMap is written such that the length of the result list can be determined from the length of the argument list (and the other way around). Similarly, the type of the elements of the list is propagated in both directions too.

````>>> ````:set -XNoMonomorphismRestriction
````>>> ````let xs = 1 .*. 'c' .*. HNil
````>>> ````:t hMap (HJust ()) xs
```hMap (HJust ()) xs :: Num y => HList '[HJust y, HJust Char]
```

These 4 examples show that the constraint on the length (2 in this case) can be applied before or after the `hMap`. That inference is independent of the direction that type information is propagated for the individual elements.

````>>> ````let asLen2 xs = xs `asTypeOf` (undefined :: HList '[a,b])
``````
````>>> ````let lr xs = asLen2 (applyAB (HMap HRead) xs)
````>>> ````let ls xs = asLen2 (applyAB (HMap HShow) xs)
````>>> ````let rl xs = applyAB (HMap HRead) (asLen2 xs)
````>>> ````let sl xs = applyAB (HMap HShow) (asLen2 xs)
``````
````>>> ````:t lr
```lr
:: (Read ..., Read ...) => HList '[String, String] -> HList '[..., ...]
```
````>>> ````:t rl
```rl
:: (Read ..., Read ...) => HList '[String, String] -> HList '[..., ...]
```
````>>> ````:t ls
```ls
:: (Show ..., Show ...) => HList '[..., ...] -> HList '[String, String]
```
````>>> ````:t sl
```sl
:: (Show ..., Show ...) => HList '[..., ...] -> HList '[String, String]
```

Constructors

 HMap f

Instances

 (HMapCxt r f a b, (~) * as (r a), (~) * bs (r b)) => ApplyAB (HMap f) as bs

hMap :: (HMapAux r f a b, SameLength' * * b a, SameLength' * * a b) => f -> r a -> r b Source

hMapL :: (HMapAux HList f a b, SameLength' * * b a, SameLength' * * a b) => f -> HList a -> HList b Source

hMap constrained to HList

newtype HMapL f Source

Constructors

 HMapL f

Instances

 (HMapCxt HList f a b, (~) * as (HList a), (~) * bs (HList b)) => ApplyAB (HMapL f) as bs

class (SameLength a b, HMapAux r f a b) => HMapCxt r f a b Source

Instances

 (SameLength * * a b, HMapAux r f a b) => HMapCxt r f a b

class HMapAux r f x y where Source

Methods

hMapAux :: SameLength x y => f -> r x -> r y Source

Instances

 HMapAux HList (HFmap f) x y => HMapAux Record f x y HMapAux Variant f xs ys => HMapAux TIC f xs ys (ApplyAB f (GetElemTy x) (GetElemTy y), IArray UArray (GetElemTy y), IArray UArray (GetElemTy x)) => HMapAux RecordU f x y HMapAux HList f ([] *) ([] *) (ApplyAB f e e', HMapAux HList f l l', SameLength * * l l') => HMapAux HList f ((:) * e l) ((:) * e' l') (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' ([] *))

#### alternative implementation

currently broken

newtype MapCar f Source

Constructors

 MapCar f

Instances

 ApplyAB f e e' => ApplyAB (MapCar f) (e, HList l) (HList ((:) * e' l))

hMapMapCar :: HFoldr (MapCar f) (HList []) l l' => f -> HList l -> l' Source

Same as `hMap` only a different implementation.

### `appEndo . mconcat . map Endo`

hComposeList :: HFoldr Comp (a -> a) l (t -> a) => HList l -> t -> a Source

````>>> ````let xs = length .*. (+1) .*. (*2) .*. HNil
````>>> ````hComposeList xs "abc"
```8
```

### sequence

class (Applicative m, SameLength a b) => HSequence m a b | a -> b, m b -> a where Source

A heterogeneous version of

`sequenceA :: (Applicative m) => [m a] -> m [a]`

Only now we operate on heterogeneous lists, where different elements may have different types `a`. In the argument list of monadic values (m a_i), although a_i may differ, the monad `m` must be the same for all elements. That's why we needed Data.HList.TypeCastGeneric2 (currently (~)). The typechecker will complain if we attempt to use hSequence on a HList of monadic values with different monads.

The `hSequence` problem was posed by Matthias Fischmann in his message on the Haskell-Cafe list on Oct 8, 2006

`Maybe`
````>>> ````hSequence \$ Just (1 :: Integer) `HCons` (Just 'c') `HCons` HNil
```Just H[1,'c']
```
````>>> ````hSequence \$  return 1 `HCons` Just  'c' `HCons` HNil
```Just H[1,'c']
```
`List`
````>>> ````hSequence \$ [1] `HCons` ['c'] `HCons` HNil
```[H[1,'c']]
```

Methods

hSequence :: HList a -> m (HList b) Source

Instances

 Applicative m => HSequence m ([] *) ([] *) ((~) (* -> *) m1 m, Applicative m, HSequence m as bs) => HSequence m ((:) * (m1 a) as) ((:) * a bs)

#### alternative implementation

hSequence2 :: (HFoldr (LiftA2 FHCons) (f (HList ([] *))) l (f a), Applicative f) => HList l -> f a Source

`hSequence2` is not recommended over `hSequence` since it possibly doesn't allow inferring argument types from the result types. Otherwise this version should do exactly the same thing.

The DataKinds version needs a little help to find the type of the return HNil, unlike the original version, which worked just fine as

`hSequence l = hFoldr ConsM (return HNil) l`

## producing homogenous lists

### map (no sequencing)

This one we implement via hFoldr

newtype Mapcar f Source

Constructors

 Mapcar f

Instances

 ((~) * l [e'], ApplyAB f e e', (~) * el (e, l)) => ApplyAB (Mapcar f) el l

type HMapOut f l e = HFoldr (Mapcar f) [e] l [e] Source

hMapOut :: forall f e l. HMapOut f l e => f -> HList l -> [e] Source

compare `hMapOut f` with `hList2List . hMap f`

### mapM

hMapM :: (Monad m, HMapOut f l (m e)) => f -> HList l -> [m e] Source

`mapM :: forall b m a. (Monad m) => (a -> m b) -> [a] -> m [b]`

Likewise for `mapM_`.

See `hSequence` if the result list should also be heterogenous.

hMapM_ :: (Monad m, HMapOut f l (m ())) => f -> HList l -> m () Source

GHC doesn't like its own type.

`hMapM_ :: forall m a f e. (Monad m, HMapOut f a (m e)) => f -> a -> m ()`

Without explicit type signature, it's Ok. Sigh. Anyway, Hugs does insist on a better type. So we restrict as follows:

# Ensure a list to contain HNats only

type family HNats l :: [HNat] Source

We do so constructively, converting the HList whose elements are Proxy HNat to [HNat]. The latter kind is unpopulated and is present only at the type level.

Instances

 type HNats ([] *) = [] HNat type HNats ((:) * (Proxy HNat n) l) = (:) HNat n (HNats l)

# Membership tests

class HMember e1 l b | e1 l -> b Source

Check to see if an HList contains an element with a given type This is a type-level only test

Instances

 HMember k e1 ([] k) False (HEq k e1 e b, HMember' k b e1 l br) => HMember k e1 ((:) k e l) br

class HMember' b0 e1 l b | b0 e1 l -> b Source

Instances

 HMember k e1 l br => HMember' k False e1 l br HMember' k True e1 l True

type family HMemberP pred e1 l :: Bool Source

The following is a similar type-only membership test It uses the user-supplied curried type equality predicate pred

Instances

 type HMemberP pred e1 ([] *) = False type HMemberP pred e1 ((:) * e l) = HMemberP' pred e1 l (ApplyR pred (e1, e))

type family HMemberP' pred e1 l pb :: Bool Source

Instances

 type HMemberP' pred e1 l (Proxy Bool False) = HMemberP pred e1 l type HMemberP' pred e1 l (Proxy Bool True) = True

hMember :: HMember e l b => Proxy e -> Proxy l -> Proxy b Source

## Another type-level membership test

class HMemberM e1 l r | e1 l -> r Source

Check to see if an element e occurs in a list l If not, return 'Nothing If the element does occur, return 'Just l1 where l1 is a type-level list without e

Instances

 HMemberM k e1 ([] k) (Nothing [k]) (HEq k e1 e b, HMemberM1 k b e1 ((:) k e l) res) => HMemberM k e1 ((:) k e l) res

class HMemberM1 b e1 l r | b e1 l -> r Source

Instances

 (HMemberM k e1 l r, HMemberM2 k r e1 ((:) k e l) res) => HMemberM1 k False e1 ((:) k e l) res HMemberM1 k True e1 ((:) k e l) (Just [k] l)

class HMemberM2 b e1 l r | b e1 l -> r Source

Instances

 HMemberM2 k (Nothing [k]) e1 l (Nothing [k]) HMemberM2 k (Just [k] l1) e1 ((:) k e l) (Just [k] ((:) k e l1))

# Find an element in a set based on HEq

class HFind1 e l n => HFind e l n | e l -> n Source

It is a pure type-level operation

Instances

 HFind1 k e l n => HFind k e l n

class HFind1 e l n | e l -> n Source

Instances

 Fail * (FieldNotFound k e1) => HFind1 k e1 ([] k) HZero (HEq k e1 e2 b, HFind2 k b e1 l n) => HFind1 k e1 ((:) k e2 l) n

class HFind2 b e l n | b e l -> n Source

Instances

 HFind2 k True e l HZero HFind1 k e l n => HFind2 k False e l (HSucc n)

## Membership test based on type equality

class HTMember e l b | e l -> b Source

could be an associated type if HEq had one

Instances

 HTMember k e ([] *) False (HEq * e e' b, HTMember * e l b', (~) Bool (HOr b b') b'') => HTMember * e ((:) * e' l) b''

hTMember :: HTMember e l b => e -> HList l -> Proxy b Source

# Intersection based on HTMember

class HTIntersect l1 l2 l3 | l1 l2 -> l3 where Source

Methods

hTIntersect :: HList l1 -> HList l2 -> HList l3 Source

Like `intersect`

Instances

 HTIntersect ([] *) l ([] *) (HTMember * h l1 b, HTIntersectBool b h t l1 l2) => HTIntersect ((:) * h t) l1 l2

class HTIntersectBool b h t l1 l2 | b h t l1 -> l2 where Source

Methods

hTIntersectBool :: Proxy b -> h -> HList t -> HList l1 -> HList l2 Source

Instances

 HTIntersect t l1 l2 => HTIntersectBool False h t l1 l2 HTIntersect t l1 l2 => HTIntersectBool True h t l1 ((:) * h l2)

# Convert between heterogeneous lists and homogeneous ones

class HList2List l e | l -> e where Source

`hMapOut id` is similar, except this function is restricted to HLists that actually contain a value (so the list produced will be nonempty). This restriction allows adding a functional dependency, which means that less type annotations can be necessary.

Methods

hList2List :: HList l -> [e] Source

list2HListSuffix :: [e] -> Maybe (HList l, [e]) Source

Instances

 HList2List ((:) * e' l) e => HList2List ((:) * e ((:) * e' l)) e HList2List ((:) * e ([] *)) e

list2HList :: HList2List l e => [e] -> Maybe (HList l) Source

listAsHList :: (HList2List l1 e1, HList2List l e, Choice p, Applicative f) => p (HList l1) (f (HList l)) -> p [e1] (f [e]) Source

`Prism [s] [t] (HList s) (HList t)`

listAsHList' :: (HList2List l e, Choice p, Applicative f) => p (HList l) (f (HList l)) -> p [e] (f [e]) Source

`Prism' [a] (HList s)`

where `s ~ HReplicateR n a`

# With `HMaybe`

## Turn list in a list of justs

class (FromHJustR (ToHJustR l) ~ l) => ToHJust l where Source

the same as `map Just`

````>>> ````toHJust (2 .*. 'a' .*. HNil)
```H[HJust 2,HJust 'a']
```
````>>> ````toHJust2 (2 .*. 'a' .*. HNil)
```H[HJust 2,HJust 'a']
```

Associated Types

type ToHJustR l :: [*] Source

Methods

toHJust :: HList l -> HList (ToHJustR l) Source

Instances

 ToHJust ([] *) ToHJust l => ToHJust ((:) * e l)

toHJust2 :: (HMapCxt r (HJust ()) a b, ToHJust a, b ~ ToHJustR a) => r a -> r b Source

alternative implementation. The Apply instance is in Data.HList.FakePrelude. A longer type could be inferred.

## Extract justs from list of maybes

class (FromHJustR (ToHJustR l) ~ l) => FromHJust l where Source

Associated Types

type FromHJustR l :: [*] Source

Instances

 FromHJust ([] *) FromHJust l => FromHJust ((:) * (HJust e) l) FromHJust l => FromHJust ((:) * HNothing l)

### alternative implementation

fromHJust2 :: HMapCxt r HFromJust a b => r a -> r b Source

This implementation is shorter.

data HFromJust Source

Constructors

 HFromJust

Instances

 (~) * hJustA (HJust a) => ApplyAB HFromJust hJustA a

# Annotated lists

Constructors

Instances

 (~) * et (e, t) => ApplyAB (HAddTag t) e et

data HRmTag Source

Constructors

 HRmTag

Instances

 (~) * e' e => ApplyAB HRmTag (e, t) e'

hAddTag :: (HMapAux r (HAddTag t) a b, SameLength' * * b a, SameLength' * * a b) => t -> r a -> r b Source

hRmTag :: (HMapAux r HRmTag a b, SameLength' * * b a, SameLength' * * a b) => r a -> r b Source

hFlag :: (HMapAux r (HAddTag (Proxy Bool True)) a b, SameLength' * * b a, SameLength' * * a b) => r a -> r b Source

Annotate list with a type-level Boolean

`hFlag :: HMapCxt (HAddTag (Proxy True)) l r => HList l -> HList r`

# Splitting by HTrue and HFalse

class HSplit l where Source

Analogus to Data.List.`partition` `snd`. See also `HPartition`

````>>> ````let (.=.) :: p x -> y -> Tagged x y; _ .=. y = Tagged y
````>>> ````hSplit \$ hTrue .=. 2 .*. hTrue .=. 3 .*. hFalse .=. 1 .*. HNil
```(H[2,3],H[1])
```

it might make more sense to instead have `LVPair Bool e` instead of `(e, Proxy Bool)` since the former has the same runtime representation as `e`

Associated Types

type HSplitT l :: [*] Source

type HSplitF l :: [*] Source

Methods

hSplit :: HList l -> (HList (HSplitT l), HList (HSplitF l)) Source

Instances

 HSplit ([] *) HSplit l => HSplit ((:) * (e, Proxy Bool False) l) HSplit l => HSplit ((:) * (e, Proxy Bool True) l) HSplit l => HSplit ((:) * (Tagged Bool False e) l) HSplit l => HSplit ((:) * (Tagged Bool True e) l)

# Splitting by Length

class (HLengthEq xs n, HAppendList1 xs ys xsys) => HSplitAt n xsys xs ys | n xsys -> xs ys, xs ys -> xsys, xs -> n where Source

`splitAt`

setup

````>>> ````let two = hSucc (hSucc hZero)
````>>> ````let xsys = hEnd \$ hBuild 1 2 3 4
``````

If a length is explicitly provided, the resulting lists are inferred

````>>> ````hSplitAt two xsys
```(H[1,2],H[3,4])
```
````>>> ````let sameLength_ :: SameLength a b => r a -> r b -> r a; sameLength_ = const
````>>> ````let len2 x = x `sameLength_` HCons () (HCons () HNil)
``````

If the first chunk of the list (a) has to be a certain length, the type of the Proxy argument can be inferred.

````>>> ````case hSplitAt Proxy xsys of (a,b) -> (len2 a, b)
```(H[1,2],H[3,4])
```

Methods

hSplitAt :: Proxy n -> HList xsys -> (HList xs, HList ys) Source

Instances

 (HSplitAt1 ([] *) n xsys xs ys, HAppendList1 * xs ys xsys, HLengthEq xs n) => HSplitAt n xsys xs ys

class HSplitAt1 accum n xsys xs ys | accum n xsys -> xs ys where Source

helper for `HSplitAt`

Methods

hSplitAt1 :: HList accum -> Proxy n -> HList xsys -> (HList xs, HList ys) Source

Instances

 HRevApp accum ([] *) xs => HSplitAt1 accum HZero ys xs ys HSplitAt1 ((:) * b accum) n bs xs ys => HSplitAt1 accum (HSucc n) ((:) * b bs) xs ys

class (SameLength' (HReplicateR n ()) xs, HLengthEq1 xs n, HLengthEq2 xs n) => HLengthEq xs n | xs -> n Source

a better way to write `HLength xs ~ n` because:

1. it works properly with ghc-7.10 (probably another example of ghc bug #10009)
2. it works backwards a bit in that if `n` is known, then `xs` can be refined:
````>>> ````undefined :: HLengthEq xs HZero => HList xs
```H[]
```

Instances

 (SameLength' * * (HReplicateR * n ()) xs, HLengthEq1 HNat xs n, HLengthEq2 HNat xs n) => HLengthEq xs n

class HLengthEq1 xs n Source

Instances

 (~) [*] xxs ([] *) => HLengthEq1 HNat xxs HZero (HLengthEq xs n, (~) [*] xxs ((:) * x xs)) => HLengthEq1 HNat xxs (HSucc n)

class HLengthEq2 xs n | xs -> n Source

Instances

 (~) HNat zero HZero => HLengthEq2 HNat ([] *) zero (HLengthEq xs n, (~) HNat sn (HSucc n)) => HLengthEq2 HNat ((:) * x xs) sn

class HStripPrefix xs xsys ys => HAppendList1 xs ys xsys | xs ys -> xsys, xs xsys -> ys Source

`HAppendList1 xs ys xsys` is the type-level way of saying `xs ++ ys == xsys`

used by `HSplitAt`

Instances

 HAppendList1 k ([] k) ys ys HAppendList1 k xs ys zs => HAppendList1 k ((:) k x xs) ys ((:) k x zs)

class HStripPrefix xs xsys ys | xs xsys -> ys Source

analog of `stripPrefix`

Instances

 HStripPrefix [k] k k ([] k) ys ys ((~) k1 x' x, HStripPrefix [k1] [k1] k xs xsys ys) => HStripPrefix [k] [k] k ((:) k x' xs) ((:) k x xsys) ys

# Conversion to and from tuples

class HTuple v t | v -> t, t -> v where Source

Methods

hToTuple :: HList v -> t Source

alternatively: `hUncurry (,,,)`

hFromTuple :: t -> HList v Source

Instances

 HTuple ([] *) () HTuple ((:) * a ((:) * b ([] *))) (a, b) HTuple ((:) * a ((:) * b ((:) * c ([] *)))) (a, b, c) HTuple ((:) * a ((:) * b ((:) * c ((:) * d ([] *))))) (a, b, c, d) HTuple ((:) * a ((:) * b ((:) * c ((:) * d ((:) * e ([] *)))))) (a, b, c, d, e) HTuple ((:) * a ((:) * b ((:) * c ((:) * d ((:) * e ((:) * f ([] *))))))) (a, b, c, d, e, f)

hTuple :: (HTuple v1 b, HTuple v a, Profunctor p, Functor f) => p a (f b) -> p (HList v) (f (HList v1)) Source

`Iso (HList v) (HList v') a b`

hTuple' :: (HTuple v b, Profunctor p, Functor f) => p b (f b) -> p (HList v) (f (HList v)) Source

`Iso' (HList v) a`

class HTails a b | a -> b, b -> a where Source

`tails`

Methods

hTails :: HList a -> HList b Source

Instances

 HTails ([] *) ((:) * (HList ([] *)) ([] *)) HTails xs ys => HTails ((:) * x xs) ((:) * (HList ((:) * x xs)) ys)

class HInits a b | a -> b, b -> a where Source

`inits`

Methods

hInits :: HList a -> HList b Source

Instances

 HInits1 a b => HInits a ((:) * (HList ([] *)) b)

class HInits1 a b | a -> b, b -> a where Source

behaves like `tail . inits`

Methods

hInits1 :: HList a -> HList b Source

Instances

 HInits1 ([] *) ((:) * (HList ([] *)) ([] *)) (HInits1 xs ys, HMapCxt HList (FHCons2 x) ys ys', (~) [*] (HMapCons x ys) ys', (~) [*] (HMapTail ys') ys) => HInits1 ((:) * x xs) ((:) * (HList ((:) * x ([] *))) ys')

data FHCons2 x Source

similar to `FHCons`

Constructors

 FHCons2 x

Instances

 ((~) * hxs (HList xs), (~) * hxxs (HList ((:) * x xs))) => ApplyAB (FHCons2 x) hxs hxxs

type family HMapCons x xxs :: [*] Source

evidence to satisfy the fundeps in HInits

Instances

 type HMapCons x ([] *) = [] * type HMapCons x ((:) * (HList a) b) = (:) * (HList ((:) * x a)) (HMapCons x b)

type family HMapTail xxs :: [*] Source

evidence to satisfy the fundeps in HInits

Instances

 type HMapTail ([] *) = [] * type HMapTail ((:) * (HList ((:) * a as)) bs) = (:) * (HList as) (HMapTail bs)

# partition

class HPartitionEq f x1 xs xi xo | f x1 xs -> xi xo where Source

`HPartitionEq f x1 xs xi xo` is analogous to

`(xi,xo) = partition (f x1) xs`

where `f` is a "function" passed in using it's instance of `HEqBy`

Methods

hPartitionEq :: Proxy f -> Proxy x1 -> HList xs -> (HList xi, HList xo) Source

Instances

 HPartitionEq k k f x1 ([] *) ([] *) ([] *) (HEqBy k * f x1 x b, HPartitionEq1 k * b f x1 x xs xi xo) => HPartitionEq k * f x1 ((:) * x xs) xi xo

class HPartitionEq1 b f x1 x xs xi xo | b f x1 x xs -> xi xo where Source

Methods

hPartitionEq1 :: Proxy b -> Proxy f -> Proxy x1 -> x -> HList xs -> (HList xi, HList xo) Source

Instances

 HPartitionEq k k1 f x1 xs xi xo => HPartitionEq1 k k False f x1 x xs xi ((:) * x xo) HPartitionEq k k1 f x1 xs xi xo => HPartitionEq1 k k True f x1 x xs ((:) * x xi) xo

# groupBy

class HGroupBy f as gs | f as -> gs, gs -> as where Source

`HGroupBy f x y` is analogous to `y = groupBy f x`

given that `f` is used by `HEqBy`

Methods

hGroupBy :: Proxy f -> HList as -> HList gs Source

Instances

 HGroupBy k f ([] *) ([] *) (HSpanEqBy k f a as fst snd, HGroupBy k f snd gs) => HGroupBy k f ((:) * a as) ((:) * (HList ((:) * a fst)) gs)

# span

class HSpanEqBy f x y fst snd | f x y -> fst snd, fst snd -> y where Source

`HSpanEq x y fst snd` is analogous to `(fst,snd) = span (== x) y`

Methods

hSpanEqBy :: Proxy f -> x -> HList y -> (HList fst, HList snd) Source

Instances

 (HSpanEqBy1 k f x y fst snd, (~) [*] (HAppendListR * fst snd) y) => HSpanEqBy k f x y fst snd

class HSpanEqBy1 f x y i o | f x y -> i o where Source

Methods

hSpanEqBy1 :: Proxy f -> x -> HList y -> (HList i, HList o) Source

Instances

 HSpanEqBy1 k f x ([] *) ([] *) ([] *) (HEqBy k * f x y b, HSpanEqBy2 k b f x y ys i o) => HSpanEqBy1 k f x ((:) * y ys) i o

class HSpanEqBy2 b f x y ys i o | b f x y ys -> i o where Source

Methods

hSpanEqBy2 :: Proxy b -> Proxy f -> x -> y -> HList ys -> (HList i, HList o) Source

Instances

 HSpanEqBy2 k False f x y ys ([] *) ((:) * y ys) HSpanEqBy1 k f x zs i o => HSpanEqBy2 k True f x y zs ((:) * y i) o

# zip

see alternative implementations in Data.HList.HZip

class HZipList x y l | x y -> l, l -> x y where Source

Methods

hZipList :: HList x -> HList y -> HList l Source

hUnzipList :: HList l -> (HList x, HList y) Source

Instances

 HZipList ([] *) ([] *) ([] *) ((~) * (x, y) z, HZipList xs ys zs) => HZipList ((:) * x xs) ((:) * y ys) ((:) * z zs)

# Monoid instance

## helper functions

Constructors

 ConstMempty

Instances

 ((~) * x (Proxy * y), Monoid y) => ApplyAB ConstMempty x y

Constructors

 UncurryMappend

Instances

 ((~) * aa (a, a), Monoid a) => ApplyAB UncurryMappend aa a