Safe Haskell | None |
---|---|
Language | Haskell2010 |
- Heterogeneous type sequences
- Basic list functions
- Reversing HLists
- A nicer notation for lists
- folds
- unfolds
- concat
- traversing HLists
- Ensure a list to contain HNats only
- Membership tests
- Staged equality for lists
- Find an element in a set based on HEq
- Intersection based on HTMember
- Convert between heterogeneous lists and homogeneous ones
- With
HMaybe
- Annotated lists
- Splitting by HTrue and HFalse
- Splitting by Length
- Conversion to and from tuples
- partition
- groupBy
- span
- zip
- Monoid instance
The HList library
(C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
Basic declarations for typeful heterogeneous lists.
- data family HList (l :: [*])
- class HProxiesFD (xs :: [*]) pxs | pxs -> xs, xs -> pxs where
- type HProxies xs = HProxiesFD xs (AddProxy xs)
- type family AddProxy (xs :: k) :: k
- type family DropProxy (xs :: k) :: k
- data ReadElement = ReadElement
- hHead :: HList (e ': l) -> e
- hTail :: HList (e ': l) -> HList l
- hLast :: HRevApp l1 ([] *) ((:) * e l) => HList l1 -> e
- class HInit xs where
- type family HLength (x :: [k]) :: HNat
- hLength :: HLengthEq l n => HList l -> Proxy n
- type family HAppendListR (l1 :: [k]) (l2 :: [k]) :: [k]
- class HAppendList l1 l2 where
- append' :: [a] -> [a] -> [a]
- hAppend' :: HFoldr FHCons v l r => HList l -> v -> r
- data FHCons = FHCons
- type family HRevAppR (l1 :: [k]) (l2 :: [k]) :: [k]
- class HRevApp l1 l2 l3 | l1 l2 -> l3 where
- class HReverse xs sx | xs -> sx, sx -> xs where
- hReverse_ :: HRevApp l1 ([] *) l3 => HList l1 -> HList l3
- hEnd :: HList l -> HList l
- hBuild :: HBuild' '[] r => r
- class HBuild' l r where
- class HFoldr f v (l :: [*]) r where
- class HScanr f z ls rs where
- class HFoldr1 f (l :: [*]) r where
- class HFoldl f (z :: *) xs (r :: *) where
- hUnfold :: (Apply f a, HUnfoldFD f (ApplyR f a) z) => f -> a -> HList z
- type HUnfold p s = HUnfoldR p (ApplyR p s)
- type family HUnfoldR p res :: [*]
- type HUnfold' p res = HUnfoldFD p (ApplyR p res) (HUnfold p res)
- class HUnfoldFD p res z | p res -> z where
- class HLengthEq es n => HReplicateFD (n :: HNat) e es | n e -> es, es -> n where
- type HReplicate n e = HReplicateFD n e (HReplicateR n e)
- type family HReplicateR (n :: HNat) (e :: k) :: [k]
- class HLengthEq r n => HReplicateF (n :: HNat) f z r | r -> n where
- class HLengthEq r n => HIterate n f z r where
- type HConcat xs = HConcatFD xs (HConcatR xs)
- hConcat :: HConcat xs => HList xs -> HList (HConcatR xs)
- type family HConcatR (a :: [*]) :: [*]
- type family UnHList a :: [*]
- class HConcatFD xxs xs | xxs -> xs where
- class HAppendFD a b ab | a b -> ab where
- newtype HMap f = HMap f
- hMap :: (HMapAux r f a b, SameLength' * * b a, SameLength' * * a b) => f -> r a -> r b
- hMapL :: (HMapAux HList f a b, SameLength' * * b a, SameLength' * * a b) => f -> HList a -> HList b
- newtype HMapL f = HMapL f
- class (SameLength a b, HMapAux r f a b) => HMapCxt r f a b
- class HMapAux (r :: [*] -> *) f (x :: [*]) (y :: [*]) where
- newtype MapCar f = MapCar f
- hMapMapCar :: HFoldr (MapCar f) (HList '[]) l l' => f -> HList l -> l'
- hComposeList :: HFoldr Comp (a -> a) l (t -> a) => HList l -> t -> a
- class (Applicative m, SameLength a b) => HSequence m a b | a -> b, m b -> a where
- hSequence2 :: (HFoldr (LiftA2 FHCons) (f (HList ([] *))) l (f a), Applicative f) => HList l -> f a
- newtype Mapcar f = Mapcar f
- type HMapOut f l e = HFoldr (Mapcar f) [e] l [e]
- hMapOut :: forall f e l. HMapOut f l e => f -> HList l -> [e]
- hMapM :: (Monad m, HMapOut f l (m e)) => f -> HList l -> [m e]
- hMapM_ :: (Monad m, HMapOut f l (m ())) => f -> HList l -> m ()
- type family HNats (l :: [*]) :: [HNat]
- hNats :: HList l -> Proxy (HNats l)
- class HMember (e1 :: k) (l :: [k]) (b :: Bool) | e1 l -> b
- class HMember' (b0 :: Bool) (e1 :: k) (l :: [k]) (b :: Bool) | b0 e1 l -> b
- type family HMemberP pred e1 (l :: [*]) :: Bool
- type family HMemberP' pred e1 (l :: [*]) pb :: Bool
- hMember :: HMember e l b => Proxy e -> Proxy l -> Proxy b
- class HMemberM (e1 :: k) (l :: [k]) (r :: Maybe [k]) | e1 l -> r
- class HMemberM1 (b :: Bool) (e1 :: k) (l :: [k]) (r :: Maybe [k]) | b e1 l -> r
- class HMemberM2 (b :: Maybe [k]) (e1 :: k) (l :: [k]) (r :: Maybe [k]) | b e1 l -> r
- class HFind1 e l l n => HFind (e :: k) (l :: [k]) (n :: HNat) | e l -> n
- class HFind1 (e :: k) (l :: [k]) (l0 :: [k]) (n :: HNat) | e l -> n
- class HFind2 (b :: Bool) (e :: k) (l :: [k]) (l0 :: [k]) (n :: HNat) | b e l -> n
- class HTMember e (l :: [*]) (b :: Bool) | e l -> b
- hTMember :: HTMember e l b => e -> HList l -> Proxy b
- class HTIntersect l1 l2 l3 | l1 l2 -> l3 where
- class HTIntersectBool (b :: Bool) h t l1 l2 | b h t l1 -> l2 where
- class HList2List l e | l -> e where
- list2HList :: HList2List l e => [e] -> Maybe (HList l)
- listAsHList :: (Applicative f, Choice p, HList2List l2 e2, HList2List l1 e1) => p (HList l2) (f (HList l1)) -> p [e2] (f [e1])
- listAsHList' :: (HList2List l e, Choice p, Applicative f) => p (HList l) (f (HList l)) -> p [e] (f [e])
- class FromHJustR (ToHJustR l) ~ l => ToHJust l where
- toHJust2 :: (HMapCxt r (HJust ()) a b, ToHJust a, b ~ ToHJustR a) => r a -> r b
- class FromHJustR (ToHJustR l) ~ l => FromHJust l where
- type FromHJustR l :: [*]
- fromHJust2 :: HMapCxt r HFromJust a b => r a -> r b
- data HFromJust = HFromJust
- data HAddTag t = HAddTag t
- data HRmTag = HRmTag
- hAddTag :: (SameLength' * * a b, SameLength' * * b a, HMapAux r (HAddTag t) a b) => t -> r a -> r b
- hRmTag :: (SameLength' * * a b, SameLength' * * b a, HMapAux r HRmTag a b) => r a -> r b
- hFlag :: (HMapAux r (HAddTag (Proxy Bool True)) a b, SameLength' * * b a, SameLength' * * a b) => r a -> r b
- class HSplit l where
- class (HLengthEq xs n, HAppendList1 xs ys xsys) => HSplitAt (n :: HNat) xsys xs ys | n xsys -> xs ys, xs ys -> xsys, xs -> n where
- class HSplitAt1 accum (n :: HNat) xsys xs ys | accum n xsys -> xs ys where
- class (SameLength' (HReplicateR n ()) xs, HLengthEq1 xs n, HLengthEq2 xs n) => HLengthEq (xs :: [*]) (n :: HNat) | xs -> n
- class HLengthEq1 (xs :: [*]) n
- class HLengthEq2 (xs :: [*]) n | xs -> n
- class HLengthGe (xs :: [*]) (n :: HNat)
- class HStripPrefix xs xsys ys => HAppendList1 (xs :: [k]) (ys :: [k]) (xsys :: [k]) | xs ys -> xsys, xs xsys -> ys
- class HStripPrefix xs xsys ys | xs xsys -> ys
- class HTake (n :: HNat) xs ys | n xs -> ys where
- class HDrop (n :: HNat) xs ys | n xs -> ys where
- class HTuple v t | v -> t, t -> v where
- hTuple :: (HTuple v2 t, HTuple v1 a, Functor f, Profunctor p) => p a (f t) -> p (HList v1) (f (HList v2))
- hTuple' :: (Profunctor p, Functor f, HTuple v a) => p a (f a) -> p (HList v) (f (HList v))
- class HTails a b | a -> b, b -> a where
- class HInits a b | a -> b, b -> a where
- class HInits1 a b | a -> b, b -> a where
- data FHCons2 x = FHCons2 x
- type family HMapCons (x :: *) (xxs :: [*]) :: [*]
- type family HMapTail (xxs :: [*]) :: [*]
- class HPartitionEq f x1 xs xi xo | f x1 xs -> xi xo where
- class HPartitionEq1 (b :: Bool) f x1 x xs xi xo | b f x1 x xs -> xi xo where
- class HGroupBy (f :: t) (as :: [*]) (gs :: [*]) | f as -> gs, gs -> as where
- class HSpanEqBy (f :: t) (x :: *) (y :: [*]) (fst :: [*]) (snd :: [*]) | f x y -> fst snd, fst snd -> y where
- class HSpanEqBy1 (f :: t) (x :: *) (y :: [*]) (i :: [*]) (o :: [*]) | f x y -> i o where
- class HSpanEqBy2 (b :: Bool) (f :: t) (x :: *) (y :: *) (ys :: [*]) (i :: [*]) (o :: [*]) | b f x y ys -> i o where
- class HZipList x y l | x y -> l, l -> x y where
- data ConstMempty = ConstMempty
- data UncurryMappend = UncurryMappend
- data UncurrySappend = UncurrySappend
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 ofundefined
, 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 #
(SameLengths * ((:) [*] x ((:) [*] y ((:) [*] xy ([] [*])))), HZipList x y xy) => HZip HList x y xy Source # | |
(SameLengths * ((:) [*] x ((:) [*] y ((:) [*] xy ([] [*])))), HZipList x y xy) => HUnzip HList x y xy Source # | |
HMapAux HList f ([] *) ([] *) Source # | |
(HSpanEqBy t f a as fst snd, HGroupBy t f snd gs) => HGroupBy t f ((:) * a as) ((:) * (HList ((:) * a fst)) gs) Source # | |
(ApplyAB f e e', HMapAux HList f l l', SameLength * * l l') => HMapAux HList f ((:) * e l) ((:) * e' l') Source # | |
HExtend e (HList l) Source # | |
HReverse l l' => HBuild' l (HList l') Source # | |
HInits1 a b => HInits a ((:) * (HList ([] *)) b) Source # | |
(Bounded x, Bounded (HList xs)) => Bounded (HList ((:) * x xs)) Source # | |
Bounded (HList ([] *)) Source # | |
(Eq x, Eq (HList xs)) => Eq (HList ((:) * x xs)) Source # | |
Eq (HList ([] *)) Source # | |
(Ord x, Ord (HList xs)) => Ord (HList ((:) * x xs)) Source # | |
Ord (HList ([] *)) Source # | |
(HProxies l, Read e, HSequence ReadP ((:) * (ReadP e) readP_l) ((:) * e l), HMapCxt HList ReadElement (AddProxy [*] l) readP_l) => Read (HList ((:) * e l)) Source # | |
Read (HList ([] *)) Source # | |
(Show e, Show (HList l)) => Show (HList ((:) * e l)) Source # | |
Show (HList ([] *)) Source # | |
(Ix x, Ix (HList xs)) => Ix (HList ((:) * x xs)) Source # | |
Ix (HList ([] *)) Source # | |
(HZip HList a a aa, HMapCxt HList UncurryMappend aa a) => Semigroup (HList a) Source # | |
(HProxies a, HMapCxt HList ConstMempty (AddProxy [*] a) a, HZip HList a a aa, HMapCxt HList UncurryMappend aa a) => Monoid (HList a) Source # | Analogous to the Monoid instance for tuples
|
(TypeRepsList (HList xs), Typeable * x) => TypeRepsList (HList ((:) * x xs)) Source # | |
TypeRepsList (HList ([] *)) Source # | |
HAppendList l1 l2 => HAppend (HList l1) (HList l2) Source # | |
ApplyAB f e e' => ApplyAB (MapCar f) (e, HList l) (HList ((:) * e' l)) Source # | |
HInits1 ([] *) ((:) * (HList ([] *)) ([] *)) Source # | |
HTails ([] *) ((:) * (HList ([] *)) ([] *)) Source # | |
Apply (FHUProj sel ns) (HList l, Proxy HNat (HSucc n)) => Apply (Proxy Bool False, FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) Source # | |
Apply (Proxy Bool True, FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) Source # | |
((~) * 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) Source # | |
Apply (FHUProj sel ns) (HList ([] *), n) Source # | |
(HConcatFD as bs, HAppendFD a bs cs) => HConcatFD ((:) * (HList a) as) cs Source # | |
(HInits1 xs ys, HMapCxt HList (FHCons2 x) ys ys', (~) [*] (HMapCons x ys) ys', (~) [*] (HMapTail ys') ys) => HInits1 ((:) * x xs) ((:) * (HList ((:) * x ([] *))) ys') Source # | |
HTails xs ys => HTails ((:) * x xs) ((:) * (HList ((:) * x xs)) ys) Source # | |
HMapUnboxF xs us => HMapUnboxF ((:) * (HList x) xs) ((:) * (RecordU x) us) Source # | |
((~) * (HList ((:) * x y)) z, HZip3 xs ys zs) => HZip3 ((:) * x xs) ((:) * (HList y) ys) ((:) * z zs) Source # | |
type HExtendR e (HList l) Source # | |
type HMapCons x ((:) * (HList a) b) Source # | |
type UnHList (HList a) Source # | |
data HList ([] *) Source # | |
type HAppendR * (HList l1) (HList l2) Source # | |
type ApplyR (Proxy Bool False, FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) Source # | |
type ApplyR (Proxy Bool True, FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) Source # | |
type ApplyR (FHUProj sel ns) (HList ([] *), n) Source # | |
type ApplyR (FHUProj sel ns) (HList ((:) * e l), Proxy HNat n) Source # | |
type HMapTail ((:) * (HList ((:) * a as)) bs) Source # | |
data HList ((:) * x xs) Source # | |
class HProxiesFD (xs :: [*]) pxs | pxs -> xs, xs -> pxs where Source #
creates a HList of Proxies
HProxiesFD ([] *) ([] *) Source # | |
HProxiesFD xs pxs => HProxiesFD ((:) * x xs) ((:) * (Proxy * x) pxs) Source # | |
type HProxies xs = HProxiesFD xs (AddProxy xs) Source #
type family AddProxy (xs :: k) :: k Source #
Add Proxy
to a type
>>>
let x = undefined :: HList (AddProxy [Char,Int])
>>>
:t x
x :: HList '[Proxy Char, Proxy Int]
data ReadElement Source #
Basic list functions
Append
type family HAppendListR (l1 :: [k]) (l2 :: [k]) :: [k] Source #
type HAppendListR k ([] k) l Source # | |
type HAppendListR k ((:) k e l) l' Source # | |
class HAppendList l1 l2 where Source #
hAppendList :: HList l1 -> HList l2 -> HList (HAppendListR l1 l2) Source #
the same as hAppend
HAppendList ([] *) l2 Source # | |
HAppendList l l' => HAppendList ((:) * x l) l' Source # | |
Alternative append
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
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
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.
foldl
class HFoldl f (z :: *) xs (r :: *) where Source #
like foldl
>>>
hFoldl (uncurry $ flip (:)) [] (1 `HCons` 2 `HCons` HNil)
[2,1]
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.
replicate
class HLengthEq es n => HReplicateFD (n :: HNat) 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]
hReplicate :: Proxy n -> e -> HList es Source #
HReplicateFD HZero e ([] *) Source # | |
(HReplicateFD n e es, (~) * e e') => HReplicateFD (HSucc n) e ((:) * e' es) Source # | |
type HReplicate n e = HReplicateFD n e (HReplicateR n e) Source #
type family HReplicateR (n :: HNat) (e :: k) :: [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
type HReplicateR k HZero e Source # | |
type HReplicateR k (HSucc n) e Source # | |
class HLengthEq r n => HReplicateF (n :: HNat) 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]
HReplicateF HZero f z ([] *) Source # | |
(ApplyAB f z fz, HReplicateF n f z r') => HReplicateF (HSucc n) f z ((:) * fz r') Source # | |
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 ())]
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"]
traversing HLists
producing HList
map
It could be implemented with hFoldr
, as we show further below
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]
HMap f |
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
HMapL f |
class (SameLength a b, HMapAux r f a b) => HMapCxt r f a b Source #
class HMapAux (r :: [*] -> *) f (x :: [*]) (y :: [*]) where Source #
hMapAux :: SameLength x y => f -> r x -> r y Source #
HMapAux HList (HFmap f) x y => HMapAux Record f x y Source # | |
HMapAux Variant f xs ys => HMapAux TIC f xs ys Source # | |
(ApplyAB f (GetElemTy x) (GetElemTy y), IArray UArray (GetElemTy y), IArray UArray (GetElemTy x)) => HMapAux RecordU f x y Source # | |
HMapAux HList f ([] *) ([] *) Source # | |
(ApplyAB f e e', HMapAux HList f l l', SameLength * * l l') => HMapAux HList f ((:) * e l) ((:) * e' l') Source # | |
(ApplyAB f te te', HMapCxt Variant f ((:) * l ls) ((:) * l' ls')) => HMapAux Variant f ((:) * te ((:) * l ls)) ((:) * te' ((:) * l' ls')) Source # | |
ApplyAB f te te' => HMapAux Variant f ((:) * te ([] *)) ((:) * te' ([] *)) Source # | |
alternative implementation
currently broken
MapCar f |
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']]
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
Mapcar f |
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 ())) => 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.
Membership tests
class HMember (e1 :: k) (l :: [k]) (b :: Bool) | e1 l -> b Source #
Check to see if an HList contains an element with a given type This is a type-level only test
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
Another type-level membership test
class HMemberM (e1 :: k) (l :: [k]) (r :: Maybe [k]) | 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
Staged equality for lists
removed. use Typeable instead
Find an element in a set based on HEq
class HFind1 e l l n => HFind (e :: k) (l :: [k]) (n :: HNat) | e l -> n Source #
It is a pure type-level operation
Membership test based on type equality
class HTMember e (l :: [*]) (b :: Bool) | e l -> b Source #
could be an associated type if HEq had one
Intersection based on HTMember
class HTIntersect l1 l2 l3 | l1 l2 -> l3 where Source #
HTIntersect ([] *) l ([] *) Source # | |
(HTMember * h l1 b, HTIntersectBool b h t l1 l2) => HTIntersect ((:) * h t) l1 l2 Source # | |
class HTIntersectBool (b :: Bool) h t l1 l2 | b h t l1 -> l2 where Source #
HTIntersect t l1 l2 => HTIntersectBool False h t l1 l2 Source # | |
HTIntersect t l1 l2 => HTIntersectBool True h t l1 ((:) * h l2) Source # | |
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.
hList2List :: HList l -> [e] Source #
list2HListSuffix :: [e] -> Maybe (HList l, [e]) Source #
HList2List ((:) * e' l) e => HList2List ((:) * e ((:) * e' l)) e Source # | |
HList2List ((:) * e ([] *)) e Source # | |
list2HList :: HList2List l e => [e] -> Maybe (HList l) Source #
listAsHList :: (Applicative f, Choice p, HList2List l2 e2, HList2List l1 e1) => p (HList l2) (f (HList l1)) -> p [e2] (f [e1]) 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']
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 #
type FromHJustR l :: [*] Source #
alternative implementation
fromHJust2 :: HMapCxt r HFromJust a b => r a -> r b Source #
This implementation is shorter.
Annotated lists
hAddTag :: (SameLength' * * a b, SameLength' * * b a, HMapAux r (HAddTag t) a b) => t -> 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
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
Splitting by Length
class (HLengthEq xs n, HAppendList1 xs ys xsys) => HSplitAt (n :: HNat) xsys xs ys | n xsys -> xs ys, xs ys -> xsys, xs -> n where Source #
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])
class HSplitAt1 accum (n :: HNat) xsys xs ys | accum n xsys -> xs ys where Source #
helper for HSplitAt
class (SameLength' (HReplicateR n ()) xs, HLengthEq1 xs n, HLengthEq2 xs n) => HLengthEq (xs :: [*]) (n :: HNat) | xs -> n Source #
a better way to write HLength xs ~ n
because:
- it works properly with ghc-7.10 (probably another example of ghc bug #10009)
- it works backwards a bit in that if
n
is known, thenxs
can be refined:
>>>
undefined :: HLengthEq xs HZero => HList xs
H[]
(SameLength' * * (HReplicateR * n ()) xs, HLengthEq1 HNat xs n, HLengthEq2 HNat xs n) => HLengthEq xs n Source # | |
class HLengthEq1 (xs :: [*]) n Source #
class HLengthEq2 (xs :: [*]) n | xs -> n Source #
class HLengthGe (xs :: [*]) (n :: HNat) Source #
HLengthGe xs n
says that HLength xs >= n
.
unlike the expression with a type family HLength,
ghc assumes xs ~ (aFresh ': bFresh)
when given a
constraint HLengthGe xs (HSucc HZero)
class HStripPrefix xs xsys ys => HAppendList1 (xs :: [k]) (ys :: [k]) (xsys :: [k]) | xs ys -> xsys, xs xsys -> ys Source #
HAppendList1 xs ys xsys
is the type-level way of saying xs ++ ys == xsys
used by HSplitAt
HAppendList1 k ([] k) ys ys Source # | |
HAppendList1 a xs ys zs => HAppendList1 a ((:) a x xs) ys ((:) a x zs) Source # | |
class HStripPrefix xs xsys ys | xs xsys -> ys Source #
analog of stripPrefix
HStripPrefix [k1] k2 k2 ([] k1) ys ys Source # | |
((~) a x' x, HStripPrefix [a] [a] k xs xsys ys) => HStripPrefix [a] [a] k ((:) a x' xs) ((:) a x xsys) ys Source # | |
take
drop
Conversion to and from tuples
class HTuple v t | v -> t, t -> v where Source #
HTuple ([] *) () Source # | |
HTuple ((:) * a ((:) * b ([] *))) (a, b) Source # | |
HTuple ((:) * a ((:) * b ((:) * c ([] *)))) (a, b, c) Source # | |
HTuple ((:) * a ((:) * b ((:) * c ((:) * d ([] *))))) (a, b, c, d) Source # | |
HTuple ((:) * a ((:) * b ((:) * c ((:) * d ((:) * e ([] *)))))) (a, b, c, d, e) Source # | |
HTuple ((:) * a ((:) * b ((:) * c ((:) * d ((:) * e ((:) * f ([] *))))))) (a, b, c, d, e, f) Source # | |
hTuple :: (HTuple v2 t, HTuple v1 a, Functor f, Profunctor p) => p a (f t) -> p (HList v1) (f (HList v2)) Source #
Iso (HList v) (HList v') a b
hTuple' :: (Profunctor p, Functor f, HTuple v a) => p a (f a) -> p (HList v) (f (HList v)) Source #
Iso' (HList v) a
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
HPartitionEq k2 k1 f x1 ([] *) ([] *) ([] *) Source # | |
(HEqBy k * f x1 x b, HPartitionEq1 k * b f x1 x xs xi xo) => HPartitionEq k * f x1 ((:) * x xs) xi xo Source # | |
class HPartitionEq1 (b :: Bool) f x1 x xs xi xo | b f x1 x xs -> xi xo where Source #
HPartitionEq k2 k1 f x1 xs xi xo => HPartitionEq1 k2 k1 False f x1 x xs xi ((:) * x xo) Source # | |
HPartitionEq k2 k1 f x1 xs xi xo => HPartitionEq1 k2 k1 True f x1 x xs ((:) * x xi) xo Source # | |
groupBy
span
class HSpanEqBy (f :: t) (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
(HSpanEqBy1 t f x y fst snd, (~) [*] (HAppendListR * fst snd) y) => HSpanEqBy t f x y fst snd Source # | |
class HSpanEqBy1 (f :: t) (x :: *) (y :: [*]) (i :: [*]) (o :: [*]) | f x y -> i o where Source #
HSpanEqBy1 t f x ([] *) ([] *) ([] *) Source # | |
(HEqBy t * f x y b, HSpanEqBy2 t b f x y ys i o) => HSpanEqBy1 t f x ((:) * y ys) i o Source # | |
class HSpanEqBy2 (b :: Bool) (f :: t) (x :: *) (y :: *) (ys :: [*]) (i :: [*]) (o :: [*]) | b f x y ys -> i o where Source #
HSpanEqBy2 t False f x y ys ([] *) ((:) * y ys) Source # | |
HSpanEqBy1 t f x zs i o => HSpanEqBy2 t True f x y zs ((:) * y i) o Source # | |
zip
see alternative implementations in Data.HList.HZip
Monoid instance
helper functions
data ConstMempty Source #
data UncurryMappend Source #
data UncurrySappend Source #