HList-0.4.1.0: Heterogeneous lists

Safe HaskellNone
LanguageHaskell2010

Data.HList.HList

Contents

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

Disadvantages:

  • 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

Advantages

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

data ReadElement Source

Constructors

ReadElement 

Instances

((~) * y (ReadP x), Read x) => ApplyAB ReadElement (Proxy * x) y 

Basic list functions

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

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

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

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

http://www.haskell.org/pipermail/haskell-cafe/2006-October/018708.html

http://www.haskell.org/pipermail/haskell-cafe/2006-October/018784.html

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

Staged equality for lists

removed. use Typeable instead

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

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

data HAddTag t Source

Constructors

HAddTag t 

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

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

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

data ConstMempty Source

Constructors

ConstMempty 

Instances

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

data UncurryMappend Source

Constructors

UncurryMappend 

Instances

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