Safe Haskell | None |
---|---|
Language | Haskell2010 |
The HList library
(C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
Some very basic technology for faking dependent types in Haskell.
- class Apply f a where
- class ApplyAB f a b where
- applyAB :: f -> a -> b
- data Fun cxt getb = Fun (forall a. FunCxt cxt a => a -> FunApp getb a)
- data Fun' cxt geta = Fun' (forall b. FunCxt cxt b => FunApp geta b -> b)
- type family FunApp fns a
- type family FunCxt cxts a :: Constraint
- data HPrint = HPrint
- data HRead = HRead
- data HShow = HShow
- data HComp g f = HComp g f
- data Comp = Comp
- newtype HSeq x = HSeq x
- data HFlip = HFlip
- newtype HFmap f = HFmap f
- newtype LiftA2 f = LiftA2 f
- data HUntag = HUntag
- data Label l = Label
- labelToProxy :: Label l -> Proxy l
- class ShowLabel l where
- hTrue :: Proxy True
- hFalse :: Proxy False
- type family HAnd t1 t2 :: Bool
- hAnd :: Proxy t1 -> Proxy t2 -> Proxy (HAnd t1 t2)
- type family HOr t1 t2 :: Bool
- hOr :: Proxy t1 -> Proxy t2 -> Proxy (HOr t1 t2)
- type family HNot x :: Bool
- class HNotFD b nb | b -> nb, nb -> b
- hNot :: HNotFD a notA => Proxy a -> Proxy notA
- class HCond t x y z | t x y -> z where
- type family HBoolEQ t1 t2 :: Bool
- data HNat
- hZero :: Proxy HZero
- hSucc :: Proxy (n :: HNat) -> Proxy (HSucc n)
- hPred :: Proxy (HSucc n) -> Proxy n
- class HNat2Integral n where
- hNat2Integral :: Integral i => Proxy n -> i
- type family HNat2Nat n :: Nat
- class HNats2Integrals ns where
- hNats2Integrals :: Integral i => Proxy ns -> [i]
- type family HNatEq t1 t2 :: Bool
- type family HLt x y :: Bool
- hLt :: Proxy x -> Proxy y -> Proxy (HLt x y)
- type family HLe x y :: Bool
- hLe :: Proxy x -> Proxy y -> Proxy (HLe x y)
- type family HDiv2 x :: HNat
- data HNothing = HNothing
- newtype HJust x = HJust x
- class HEq x y b | x y -> b
- type HEqK x y b = HEq (Proxy x) (Proxy y) b
- hEq :: HEq x y b => x -> y -> Proxy b
- class HEqByFn f => HEqBy f x y b | f x y -> b
- class HEqByFn f
- type Arity f n = (ArityFwd f n, ArityRev f n)
- class ArityFwd f n | f -> n
- class ArityRev f n
- class HCast x y where
- class HCast1 b x y where
- class Fail x
- data ExtraField l
- data FieldNotFound l
- type TypeablePolyK a = Typeable a
- class SameLength' es1 es2
- class (SameLength' x y, SameLength' y x) => SameLength x y where
- sameLength :: (r x `p` f (q y)) -> r x `p` f (q y)
- asLengthOf :: SameLength x y => r x -> s y -> r x
- type family SameLengths xs :: Constraint
- class SameLabels x y
- sameLabels :: SameLabels x y => p (r x) (f (q y)) -> p (r x) (f (q y))
- class HAllTaggedLV ps
- type family ZipTagged ts vs :: [*]
- module Data.Proxy
- module Data.Tagged
- class Monoid a where
A heterogeneous apply operator
simpler/weaker version where type information only propagates forward
with this one. applyAB
defined below, is more complicated / verbose to define,
but it offers better type inference. Most uses have been converted to
applyAB
, so there is not much that can be done with Apply
.
HLookupByHNat n l => Apply (FHLookupByHNat l) (Proxy HNat n) | |
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) |
Polymorphic functions are not first-class in haskell. An example of this is:
f op = (op (1 :: Double), op (1 :: Int))
RankNTypes
One solution is to enable `-XRankNTypes` and then write a type signature which might be `f :: (forall a. Num a => a -> a)`. This does not work in the context of HList, since we want to use functions that do not necessarily fall into the pattern of (forall a. c a => a -> a).
MultipleArguments
Another solution is to rewrite op
to look like
f op1 op2 = (op1 (1:: Double), op2 (1 :: Int))
In some sense this approach works (see HZip), but the result
is constrained to as many function applications as you are willing to
write (ex. a function that works for records of six entries would
look like hBuild f f f f f f
).
Defunctionalization
Therefore the selected solution is to write an instance of ApplyAB
for a data
type that takes the place of the original function. In other words,
data Fn = Fn instance ApplyAB Fn a b where applyAB Fn a = actual_fn a
Normally you would have been able to pass around the definition actual_fn.
Type inference / Local functional dependencies
Note that class ApplyAB
has three parameters and no functional dependencies.
Instances should be written in the style:
instance (int ~ Int, double ~ Double) => ApplyAB Fn int double where applyAB _ = fromIntegral
rather than the more natural
instance ApplyAB Fn Int Double
The first instance allows types to be inferred as if we had
class ApplyAB a b c | a -> b c
, while the second instance
only matches if ghc already knows that it needs
ApplyAB Fn Int Double
. Since applyAB Fn :: Int -> Double
has a monomorphic type, this trimmed down example does not
really make sense because applyAB (fromIntegral :: Int -> Double)
is exactly the same. Nontheless, the other uses of ApplyAB
follow this pattern, and the benefits are seen when the type of
applyAB Fn
has at least one type variable.
Additional explanation can be found in local functional dependencies
AmbiguousTypes
Note that ghc only allows AllowAmbiguousTypes when a type signature is provided. Thus expressions such as:
data AddJust = AddJust instance (y ~ Maybe x) => ApplyAB AddJust x y where applyAB _ x = Just x twoJustsBad = hMap AddJust . hMap AddJust -- ambiguous type
Are not accepted without a type signature that references the intermediate "b":
twoJusts :: forall r a b c. (HMapCxt r AddJust a b, HMapCxt r AddJust b c) => r a -> r c twoJusts a = hMap AddJust (hMap AddJust a :: r b)
An apply class with functional dependencies
class ApplyAB' f a b | f a -> b, f b -> a
Or with equivalent type families
class (GetB f a ~ b, GetA f b ~ a) => ApplyAB' f a b
would not require an annotation for twoJusts
. However,
not all instances of ApplyAB will satisfy those functional
dependencies, and thus the number of classes would proliferate.
Furthermore, inference does not have to be in one direction
only, as the example of HMap
shows.
class ApplyAB f a b where Source
No constraints on result and argument types
(~) * (Tagged k t x) tx => ApplyAB HUntag tx x | |
((~) * f1 (a -> b -> c), (~) * f2 (b -> a -> c)) => ApplyAB HFlip f1 f2 | |
((~) * y y', (~) * fg (x -> y, y' -> z), (~) * r (x -> z)) => ApplyAB Comp fg r | |
((~) * String string, Show a) => ApplyAB HShow a string | |
((~) * String string, Read a) => ApplyAB HRead string a | |
((~) * io (IO ()), Show x) => ApplyAB HPrint x io | |
((~) * aa (a, a), Monoid a) => ApplyAB UncurryMappend aa a | |
((~) * x (Proxy * y), Monoid y) => ApplyAB ConstMempty x y | |
(~) * hJustA (HJust a) => ApplyAB HFromJust hJustA a | |
((~) * x (e, HList l), (~) * y (HList ((:) * e l))) => ApplyAB FHCons x y | |
(HZip3 a b c, (~) * x (HList a, HList b), (~) * y (HList c)) => ApplyAB HZipF x y | |
(~) * tx (Tagged k t x) => ApplyAB TaggedFn x tx | |
((~) * x (Tagged k t (Maybe e), [Variant v]), (~) * y [Variant ((:) * (Tagged k t e) v)], MkVariant k t e ((:) * (Tagged k t e) v)) => ApplyAB HMaybiedToVariantFs x y | |
(~) * y (Tagged k t (Maybe e)) => ApplyAB ConstTaggedNothing x y | |
((~) * mx (Maybe x), (~) * my (Maybe y), HCast y x) => ApplyAB HCastF mx my | |
((~) * ee (e, e), Eq e, (~) * bool Bool) => ApplyAB UncurryEq ee bool | |
((~) * x (Tagged k l v), (~) * y (HList ((:) * (Label k l) ((:) * v ([] *))))) => ApplyAB TaggedToKW x y | |
((~) * ux (RecordU x), (~) * hx (HList x), RecordUToRecord x) => ApplyAB BoxF ux hx | |
((~) * hx (HList x), (~) * ux (RecordU x), RecordToRecordU x) => ApplyAB UnboxF hx ux | |
(~) * e' e => ApplyAB HRmTag (e, t) e' | |
((~) * y (ReadP x), Read x) => ApplyAB ReadElement (Proxy * x) y | |
(Read v, ShowLabel k l, (~) * x (Tagged k l v), (~) * (ReadP x) y) => ApplyAB ReadComponent (Proxy * x) y | |
(~) * hJustA (HJust a) => ApplyAB (HJust t) a hJustA |
|
(ApplyAB f (x, y) z, (~) * mz (m z), (~) * mxy (m x, m y), Applicative m) => ApplyAB (LiftA2 f) mxy mz | |
((~) * x (t a), (~) * y (t b), Functor t, ApplyAB f a b) => ApplyAB (HFmap f) x y | |
(Monad m, ApplyAB f x fx, (~) * fx (m ()), (~) * pair (x, m ()), ApplyAB f x (m ())) => ApplyAB (HSeq f) pair fx | |
((~) * hxs (HList xs), (~) * hxxs (HList ((:) * x xs))) => ApplyAB (FHCons2 x) hxs hxxs | |
(~) * et (e, t) => ApplyAB (HAddTag t) e et | |
((~) * l [e'], ApplyAB f e e', (~) * el (e, l)) => ApplyAB (Mapcar f) el l | |
(HMapCxt HList f a b, (~) * as (HList a), (~) * bs (HList b)) => ApplyAB (HMapL f) as bs | |
(HMapCxt r f a b, (~) * as (r a), (~) * bs (r b)) => ApplyAB (HMap f) as bs | |
(HMapCxt Record f x y, (~) * rx (Record x), (~) * ry (Record y)) => ApplyAB (HMapR f) rx ry | |
((~) * vx (Variant x), (~) * vy (Variant y), HMapAux Variant (HFmap f) x y, SameLength * * x y) => ApplyAB (HMapV f) vx vy | apply a function to all values that could be in the variant. |
(Data b, (~) * x (t, c (b -> r)), (~) * y (c r)) => ApplyAB (GunfoldK c) x y | |
(Data d, (~) * (c (d -> b), d) x, (~) * (c b) y) => ApplyAB (GfoldlK c) x y | |
ApplyAB f e e' => ApplyAB (MapCar f) (e, HList l) (HList ((:) * e' l)) | |
((~) * x' x, (~) * y' y) => ApplyAB (x' -> y') x y | note this function will only be available at a single type
(that is, |
(ApplyAB f a b, ApplyAB g b c) => ApplyAB (HComp g f) a c | |
(FunCxt k cxt b, (~) * (FunApp k1 geta b) a) => ApplyAB (Fun' k k cxt geta) a b | |
(FunCxt k cxt a, (~) * (FunApp k1 getb a) b) => ApplyAB (Fun k k cxt getb) a b |
Fun
can be used instead of writing a new instance of
ApplyAB
. Refer to the definition/source for the the most
concise explanation. A more wordy explanation is given below:
A type signature needs to be provided on Fun
to make it work.
Depending on the kind of the parameters to Fun
, a number of
different results happen.
ex1
A list of kind [* -> Constraint]
produces those
constraints on the argument type:
>>>
:set -XDataKinds
>>>
let plus1f x = if x < 5 then x+1 else 5
>>>
let plus1 = Fun plus1f :: Fun '[Num, Ord] '()
>>>
:t applyAB plus1
applyAB plus1 :: (Num b, Ord b) => b -> b
>>>
let xs = [1 .. 8]
>>>
map (applyAB plus1) xs == map plus1f xs
True
Also note the use of '()
to signal that the result
type is the same as the argument type.
A single constraint can also be supplied:
>>>
let succ1 = Fun succ :: Fun Enum '()
>>>
:t applyAB succ1
applyAB succ1 :: Enum b => b -> b
>>>
let just = Fun Just :: Fun '[] Maybe
>>>
:t applyAB just
applyAB just :: a -> Maybe a
see Fun
. The only difference here is that the argument
type is calculated from the result type.
>>>
let rd = Fun' read :: Fun' Read String
>>>
:t applyAB rd
applyAB rd :: Read b => [Char] -> b
>>>
let fromJust' = Fun' (\(Just a) -> a) :: Fun' '[] Maybe
>>>
:t applyAB fromJust'
applyAB fromJust' :: Maybe b -> b
Note this use of Fun' means we don't have to get the b out of Maybe b
,
type family FunCxt cxts a :: Constraint Source
type FunCxt * cxt a = (~) * cxt a | |
type FunCxt () cxt a = () | should there be so many ways to write no constraint? |
type FunCxt [k] ([] k) a = () | |
type FunCxt [* -> Constraint] ((:) (* -> Constraint) x xs) a = (x a, FunCxt [* -> Constraint] xs a) | |
type FunCxt (* -> Constraint) cxt a = cxt a |
Simple useful instances of Apply
print. An alternative implementation could be:
>>>
let hPrint = Fun print :: Fun Show (IO ())
This produces:
>>>
:t applyAB hPrint
applyAB hPrint :: Show a => a -> IO ()
read
>>>
applyAB HRead "5.0" :: Double
5.0
Compose two instances of ApplyAB
>>>
applyAB (HComp HRead HShow) (5::Double) :: Double
5.0
HComp g f | g . f |
app Comp (f,g) = g . f
. Works like:
>>>
applyAB Comp (succ, pred) 'a'
'a'
>>>
applyAB Comp (toEnum :: Int -> Char, fromEnum) 10
10
Note that defaulting will sometimes give you the wrong thing
used to work (with associated types calculating result/argument types) >>> applyAB Comp (fromEnum, toEnum) 'a' *** Exception: Prelude.Enum.().toEnum: bad argument
((a,b) -> f a >> b)
HSeq x |
HFmap f |
LiftA2 f |
(ApplyAB f (x, y) z, (~) * mz (m z), (~) * mxy (m x, m y), Applicative m) => ApplyAB (LiftA2 f) mxy mz |
Proxy
see Data.Proxy
A special Proxy
for record labels, polykinded
HEqBy * k HLeFn x y b => HEqBy * * HLeFn (Label k x) (Label k y) b | |
(~) * (Label k t) (Label Symbol t') => SameLabels * Symbol (Label k t) t' | |
(~) * (Label k t) (Label k1 t') => SameLabels * * (Label k t) (Label k t') | |
(~) * (Label k t) (Label k1 t') => SameLabels * * (Label k t) (Tagged k t' a) | |
(~) * (Label k t) (Label * (Lbl ix ns n)) => SameLabels * * (Label k t) (Lbl ix ns n) | |
Show desc => Show (Label * (Lbl x ns desc)) | |
IsKeyFN (Label Symbol s -> a -> b) True | labels that impose no restriction on the type of the (single) argument which follows
|
HExtend (Label * (Lbl n ns desc)) (Proxy [Symbol] ((:) Symbol x xs)) | Mixing two label kinds means we have to include
|
HExtend (Label * (Lbl n ns desc)) (Proxy [*] ((:) * (Lbl n' ns' desc') xs)) | If possible, Label is left off:
|
HExtend (Label Nat y) (Proxy [Symbol] ((:) Symbol x xs)) | |
HExtend (Label Nat y) (Proxy [*] ((:) * x xs)) | |
HExtend (Label Nat y) (Proxy [Nat] ((:) Nat x xs)) | |
HExtend (Label Symbol y) (Proxy [Nat] ((:) Nat x xs)) | |
HExtend (Label Symbol y) (Proxy [*] ((:) * x xs)) | Mixing two label kinds means we have to include
|
HExtend (Label Symbol y) (Proxy [Symbol] ((:) Symbol x xs)) |
|
HExtend (Label k x) (Proxy [*] ([] *)) | to keep types shorter, ghc-7.6 does not accept |
type UnLabel k proxy ((:) * (Label k x) xs) = (:) k x (UnLabel k proxy xs) | |
type ZipTagged * ((:) * (Label k t) ts) ((:) * v vs) = (:) * (Tagged k t v) (ZipTagged * ts vs) | |
type HExtendR (Label * (Lbl n ns desc)) (Proxy [Symbol] ((:) Symbol x xs)) = Proxy [*] ((:) * (Label * (Lbl n ns desc)) (MapLabel Symbol ((:) Symbol x xs))) | |
type HExtendR (Label * (Lbl n ns desc)) (Proxy [*] ((:) * (Lbl n' ns' desc') xs)) = Proxy [*] ((:) * (Lbl n ns desc) ((:) * (Lbl n' ns' desc') xs)) | |
type HExtendR (Label Nat y) (Proxy [Symbol] ((:) Symbol x xs)) = Proxy [*] ((:) * (Label Nat y) (MapLabel Symbol ((:) Symbol x xs))) | |
type HExtendR (Label Nat y) (Proxy [*] ((:) * x xs)) = Proxy [*] ((:) * (Label Nat y) (MapLabel * ((:) * x xs))) | |
type HExtendR (Label Nat y) (Proxy [Nat] ((:) Nat x xs)) = Proxy [Nat] ((:) Nat y ((:) Nat x xs)) | |
type HExtendR (Label Symbol y) (Proxy [Nat] ((:) Nat x xs)) = Proxy [*] ((:) * (Label Symbol y) (MapLabel Nat ((:) Nat x xs))) | |
type HExtendR (Label Symbol y) (Proxy [*] ((:) * x xs)) = Proxy [*] ((:) * (Label Symbol y) (MapLabel * ((:) * x xs))) | |
type HExtendR (Label Symbol y) (Proxy [Symbol] ((:) Symbol x xs)) = Proxy [Symbol] ((:) Symbol y ((:) Symbol x xs)) | |
type HExtendR (Label k x) (Proxy [*] ([] *)) = Proxy [k] ((:) k x ([] k)) | |
type LabelsOf ((:) * (Label k l) r) = (:) * (Label k l) (LabelsOf r) |
labelToProxy :: Label l -> Proxy l Source
Booleans
GHC already lifts booleans, defined as
data Bool = True | False
to types: Bool becomes kind and True and False (also denoted by 'True and 'False) become nullary type constructors.
The above line is equivalent to
data HTrue data HFalse
class HBool x instance HBool HTrue instance HBool HFalse
Value-level proxies
Conjunction
Disjunction
Compare with the original code based on functional dependencies:
class (HBool t, HBool t', HBool t'') => HOr t t' t'' | t t' -> t'' where hOr :: t -> t' -> t''
instance HOr HFalse HFalse HFalse where hOr _ _ = hFalse
instance HOr HTrue HFalse HTrue where hOr _ _ = hTrue
instance HOr HFalse HTrue HTrue where hOr _ _ = hTrue
instance HOr HTrue HTrue HTrue where hOr _ _ = hTrue
Boolean equivalence
Naturals
The data type to be lifted to the type level
Typeable HNat HZero | |
(~) [*] xxs ([] *) => HLengthEq1 HNat xxs HZero | |
(~) Bool (HLe x y) b => HEqBy * HNat HLeFn x y b | |
(HLengthEq xs n, (~) [*] xxs ((:) * x xs)) => HLengthEq1 HNat xxs (HSucc n) | |
(~) HNat zero HZero => HLengthEq2 HNat ([] *) zero | |
HFindMany k ([] k) r ([] HNat) | |
(HLengthEq xs n, (~) HNat sn (HSucc n)) => HLengthEq2 HNat ((:) * x xs) sn | |
(HFind k l r n, HFindMany k ls r ns) => HFindMany k ((:) k l ls) r ((:) HNat n ns) | |
HNats2Integrals ([] HNat) | |
HTypes2HNats [*] [*] ([] *) l ([] HNat) | And lift to the list of types |
(HType2HNat * e l n, HTypes2HNats [*] [*] es l ns) => HTypes2HNats [*] [*] ((:) * e es) l ((:) HNat n ns) | |
HLookupByHNat n l => Apply (FHLookupByHNat l) (Proxy HNat n) | |
HNat2Integral n => Show (Proxy HNat n) | |
Typeable (HNat -> * -> * -> *) Lbl | |
Typeable (HNat -> HNat) HSucc | |
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) | |
(HNats2Integrals ns, HNat2Integral n) => HNats2Integrals ((:) HNat n ns) | |
(HNat2Integral n, (~) * (HLookupByHNatR n u) le, (~) * le (Tagged k l e), IArray UArray e, (~) * e (GetElemTy u)) => HLookupByHNatUS1 (Left HNat HNat t) n u us le | |
HLookupByHNatUS t us e => HLookupByHNatUS1 (Right HNat HNat t) n u us e | |
type KMember n ([] HNat) = False | |
type KMember n ((:) HNat n1 l) = HOr (HNatEq n n1) (KMember n l) | |
type ApplyR (FHLookupByHNat l) (Proxy HNat n) = HLookupByHNatR n l | |
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 HNats ((:) * (Proxy HNat n) l) = (:) HNat n (HNats l) |
class HNat2Integral n where Source
hNat2Integral :: Integral i => Proxy n -> i Source
KnownNat (HNat2Nat n) => HNat2Integral n |
class HNats2Integrals ns where Source
hNats2Integrals :: Integral i => Proxy ns -> [i] Source
HNats2Integrals ([] HNat) | |
(HNats2Integrals ns, HNat2Integral n) => HNats2Integrals ((:) HNat n ns) |
type family HNatEq t1 t2 :: Bool Source
Equality on natural numbers (eventually to be subsumed by the universal polykinded HEq)
Maybies
We cannot use lifted Maybe since the latter are not populated
HJust x |
(Apply p s, HUnfoldFD p (ApplyR p s) z) => HUnfoldFD p (HJust (e, s)) ((:) * e z) | |
Show x => Show (HJust x) | |
(~) * hJustA (HJust a) => ApplyAB (HJust t) a hJustA |
|
FromHJust l => FromHJust ((:) * (HJust e) l) | |
type HUnfoldR p (HJust (e, s)) = (:) * e (HUnfoldR p (ApplyR p s)) | |
type FromHJustR ((:) * (HJust e) l) = (:) * e (FromHJustR l) |
Polykinded Equality for types
class HEq x y b | x y -> b Source
We have to use Functional dependencies for now, for the sake of the generic equality.
type HEqK x y b = HEq (Proxy x) (Proxy y) b Source
Equality for types that may have different kinds. This definition
allows operations on Record [Tagged "x" a, Tagged 2 b]
to work
as expected.
class HEqByFn f => HEqBy f x y b | f x y -> b Source
this class generalizes HEq by allowing the choice of f
to allow
equating only part of x and y
((~) * txv (Tagged k x v), (~) * tyw (Tagged k1 y w), HEq * v w b) => HEqBy * * EqTagValue txv tyw b | |
(~) Bool ((<=?) x y) b => HEqBy * Nat HLeFn x y b | only in ghc >= 7.7 |
(HEq Ordering (CmpSymbol x y) GT nb, (~) Bool (HNot nb) b) => HEqBy * Symbol HLeFn x y b | only in ghc >= 7.7
|
(~) Bool (HLe x y) b => HEqBy * HNat HLeFn x y b | |
HEqBy * k HLeFn x y b => HEqBy * * HLeFn (Proxy k x) (Proxy k y) b | |
HEqBy * k HLeFn x y b => HEqBy * * HLeFn (Label k x) (Label k y) b | |
HEqBy * k HLeFn x y b => HEqBy * * HLeFn (Tagged k x v) (Tagged k y w) b | |
(HEqBy * HNat HLeFn n m b, (~) * ns ns') => HEqBy * * HLeFn (Lbl n ns desc) (Lbl m ns' desc') b | Data.HList.Label3 labels can only be compared if they belong to the same namespace. |
(HEqBy k1 k le y x b1, (~) Bool (HNot b1) b2) => HEqBy * k (HNeq k le) x y b2 | |
HEqBy k1 k f y x b => HEqBy * k (HDown k f) x y b |
Every instance of this class should have an instance of HEqBy
Arity
given the number of arguments a function can take, make sure the function type actually matches
Staged equality
Type-safe cast -- no longer need. We use a a ~ b
Cast
Error messages
Uses of fail
these could be replaced by `'("helpful message", l)`, but these look better.
data ExtraField l Source
data FieldNotFound l Source
Fail * (FieldNotFound k l) => HasField k l (Record ([] *)) (FieldNotFound k l) |
type TypeablePolyK a = Typeable a Source
Constraining Lists
Length
class SameLength' es1 es2 Source
Ensure two lists have the same length. We do case analysis on the first one (hence the type must be known to the type checker). In contrast, the second list may be a type variable.
(~) [k1] es2 ([] k1) => SameLength' k k ([] k) es2 | |
(SameLength' k k1 xs ys, (~) [k1] es2 ((:) k1 y ys)) => SameLength' k k ((:) k x xs) es2 |
class (SameLength' x y, SameLength' y x) => SameLength x y where Source
symmetrical version of SameLength'
. Written as a class instead of
type SameLength a b = (SameLength' a b, SameLength' b a)
since ghc expands type synonyms, but not classes (and it seems to have the same result)
Nothing
sameLength :: (r x `p` f (q y)) -> r x `p` f (q y) Source
SameLength x y => Equality (r x) (q y) (r x) (q y)
used like simple
, except it restricts
the type-level lists involved to have the same length,
without fixing the type of container or the elements
in the list.
(SameLength' k k1 x y, SameLength' k1 k y x) => SameLength k k x y |
asLengthOf :: SameLength x y => r x -> s y -> r x Source
type family SameLengths xs :: Constraint Source
type SameLengths k ([] [k]) = () | |
type SameLengths k ((:) [k] x ([] [k])) = () | |
type SameLengths k ((:) [k] x ((:) [k] y ys)) = (SameLength k k x y, SameLengths k ((:) [k] y ys)) |
Labels
class SameLabels x y Source
SameLabels * k (Label Symbol t) s => SameLabels Symbol k t s | |
(~) * (Label k t) (Label Symbol t') => SameLabels * Symbol (Label k t) t' | |
(~) * (Label k t) (Label k1 t') => SameLabels * * (Label k t) (Label k t') | |
(~) * (Label k t) (Label k1 t') => SameLabels * * (Label k t) (Tagged k t' a) | |
(~) * (Label k t) (Label * (Lbl ix ns n)) => SameLabels * * (Label k t) (Lbl ix ns n) | |
SameLabels * k (Label k1 t) s => SameLabels * k (Tagged k t a) s | |
SameLabels [k] [k] ([] k) ([] k) | |
SameLabels [k] [k] ([] k) ((:) k x xs) | |
SameLabels [k] [k] ((:) k x xs) ([] k) | |
(SameLabels k k1 x y, SameLabels [k] [k1] xs ys) => SameLabels [k] [k] ((:) k x xs) ((:) k y ys) |
sameLabels :: SameLabels x y => p (r x) (f (q y)) -> p (r x) (f (q y)) Source
sameLabels
constrains the type of an optic, such that the labels
(t
in Tagged t a
) are the same. x
or y
may have more elements
than the other, in which case the elements at the end
of the longer list do not have their labels constrained.
see also sameLength
A list has only Tagged values
class HAllTaggedLV ps Source
The Record
, Variant
, TIP
, TIC
type constructors only make
sense when they are applied to an instance of this class
HAllTaggedLV ([] *) | |
(HAllTaggedLV xs, (~) * x (Tagged k t v)) => HAllTaggedLV ((:) * x xs) |
type family ZipTagged ts vs :: [*] Source
see Data.HList.Record.zipTagged
type ZipTagged k ([] k) ([] *) = [] * | |
type ZipTagged * ((:) * (Label k t) ts) ((:) * v vs) = (:) * (Tagged k t v) (ZipTagged * ts vs) | |
type ZipTagged * ((:) * (Lbl ix ns n) ts) ((:) * v vs) = (:) * (Tagged * (Lbl ix ns n) v) (ZipTagged * ts vs) | |
type ZipTagged Symbol ((:) Symbol t ts) ((:) * v vs) = (:) * (Tagged Symbol t v) (ZipTagged Symbol ts vs) |
module Data.Proxy
module Data.Tagged
class Monoid a where
The class of monoids (types with an associative binary operation that has an identity). Instances should satisfy the following laws:
mappend mempty x = x
mappend x mempty = x
mappend x (mappend y z) = mappend (mappend x y) z
mconcat =
foldr
mappend mempty
The method names refer to the monoid of lists under concatenation, but there are many other instances.
Minimal complete definition: mempty
and mappend
.
Some types can be viewed as a monoid in more than one way,
e.g. both addition and multiplication on numbers.
In such cases we often define newtype
s and make those instances
of Monoid
, e.g. Sum
and Product
.
mempty :: a
Identity of mappend
mappend :: a -> a -> a
An associative operation
mconcat :: [a] -> a
Fold a list using the monoid.
For most types, the default definition for mconcat
will be
used, but the function is included in the class definition so
that an optimized version can be provided for specific types.
Monoid Ordering | |
Monoid () | |
Monoid All | |
Monoid Any | |
Monoid Text | |
Monoid Text | |
Monoid [a] | |
Monoid a => Monoid (Dual a) | |
Monoid (Endo a) | |
Num a => Monoid (Sum a) | |
Num a => Monoid (Product a) | |
Monoid (First a) | |
Monoid (Last a) | |
Monoid a => Monoid (Maybe a) | Lift a semigroup into |
(Ord a, Bounded a) => Monoid (Min a) | |
(Ord a, Bounded a) => Monoid (Max a) | |
Monoid m => Monoid (WrappedMonoid m) | |
Semigroup a => Monoid (Option a) | |
(Hashable a, Eq a) => Monoid (HashSet a) | |
(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
|
Monoid (HList r) => Monoid (Record r) | |
Monoid (HList a) => Monoid (TIP a) | |
(Monoid x, Monoid (Variant ((:) * a b))) => Monoid (Variant ((:) * (Tagged k t x) ((:) * a b))) | XXX check this mappend is legal |
(Unvariant ((:) * (Tagged k t x) ([] *)) x, Monoid x) => Monoid (Variant ((:) * (Tagged k t x) ([] *))) | |
Monoid (Variant l) => Monoid (TIC l) | |
Monoid b => Monoid (a -> b) | |
(Monoid a, Monoid b) => Monoid (a, b) | |
Monoid a => Monoid (Const a b) | |
Monoid (Proxy * s) | |
(Eq k, Hashable k) => Monoid (HashMap k v) | |
Typeable (* -> Constraint) Monoid | |
(Monoid a, Monoid b, Monoid c) => Monoid (a, b, c) | |
Monoid a => Monoid (Tagged k s a) | |
(Monoid a, Monoid b, Monoid c, Monoid d) => Monoid (a, b, c, d) | |
(Monoid a, Monoid b, Monoid c, Monoid d, Monoid e) => Monoid (a, b, c, d, e) |