HList-0.3.4.1: Heterogeneous lists

Safe HaskellNone
LanguageHaskell2010

Data.HList.FakePrelude

Contents

Description

The HList library

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

Some very basic technology for faking dependent types in Haskell.

Synopsis

A heterogeneous apply operator

class Apply f a where Source

simpler/weaker version where type information only propagates forward with this one. app defined below, is more complicated / verbose to define, but it offers better type inference. Most uses have been converted to app, so there is not much that can be done with Apply.

Minimal complete definition

Nothing

Associated Types

type ApplyR f a :: * Source

Methods

apply :: f -> a -> ApplyR f a Source

Instances

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. One 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. Additional explanation can be found in local functional dependencies

class ApplyAB f a b where Source

No constraints on result and argument types

Minimal complete definition

Nothing

Methods

applyAB :: f -> a -> b Source

Instances

((~) * 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 
(~) * 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 
((~) * (Tagged k l (Proxy * t)) a, (~) * b (Tagged k l (Maybe t))) => ApplyAB HMaybeF a b 
(~) * e' e => ApplyAB HRmTag (e, t) e' 
(~) * hJustA (HJust a) => ApplyAB (HJust t) a hJustA

HJust () is a placeholder for a function that applies the HJust constructor

(Monad m, ApplyAB f x fx, (~) * fx (m ()), (~) * pair (x, m ()), ApplyAB f x (m ())) => ApplyAB (HSeq f) pair fx 
(~) * et (e, t) => ApplyAB (HAddTag t) e et 
((~) * l [e'], ApplyAB f e e', (~) * el (e, l)) => ApplyAB (Mapcar f) el l 
(ApplyAB f (x, y) z, (~) * mz (m z), (~) * mxy (m x, m y), Applicative m) => ApplyAB (LiftA2 f) mxy mz 
HMapCxt f as bs as' bs' => ApplyAB (HMap f) as bs 
(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, hMap succ will only work on HList that contain only one type)

(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 plus1 = Fun (\x -> if x < 5 then x+1 else 5) :: Fun '[Num, Ord] '()
>>> :t applyAB plus1
applyAB plus1 :: (Num a, Ord a) => a -> a

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 a => a -> a
>>> let just = Fun Just :: Fun '[] Maybe
>>> :t applyAB just
applyAB just :: a -> Maybe a

data Fun cxt getb Source

Constructors

Fun (forall a. FunCxt cxt a => a -> FunApp getb a) 

Instances

(FunCxt k cxt a, (~) * (FunApp k1 getb a) b) => ApplyAB (Fun k k cxt getb) a b 

data Fun' cxt geta Source

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,

Constructors

Fun' (forall b. FunCxt cxt b => FunApp geta b -> b) 

Instances

(FunCxt k cxt b, (~) * (FunApp k1 geta b) a) => ApplyAB (Fun' k k cxt geta) a b 

type family FunApp fns a Source

Instances

type FunApp * fn a = fn 
type FunApp () fn a = a 
type FunApp (* -> *) fn a = fn a 

type family FunCxt cxts a :: Constraint Source

Instances

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

data HPrint Source

print. An alternative implementation could be:

>>> let hPrint = Fun print :: Fun Show (IO ())

This produces:

>>> :t applyAB hPrint
applyAB hPrint :: Show a => a -> IO ()

Constructors

HPrint 

Instances

((~) * io (IO ()), Show x) => ApplyAB HPrint x io 

data HRead Source

read

>>> applyAB HRead "5.0" :: Double
5.0

Constructors

HRead 

Instances

((~) * String string, Read a) => ApplyAB HRead string a 

data HShow Source

show

Constructors

HShow 

Instances

((~) * String string, Show a) => ApplyAB HShow a string 

data HComp g f Source

Compose two instances of ApplyAB

>>> applyAB (HComp HRead HShow) (5::Double) :: Double
5.0

Constructors

HComp g f
g . f

Instances

(ApplyAB f a b, ApplyAB g b c) => ApplyAB (HComp g f) a c 

data Comp Source

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

Constructors

Comp 

Instances

((~) * y y', (~) * fg (x -> y, y' -> z), (~) * r (x -> z)) => ApplyAB Comp fg r 

newtype HSeq x Source

((a,b) -> f a >> b)

Constructors

HSeq x 

Instances

(Monad m, ApplyAB f x fx, (~) * fx (m ()), (~) * pair (x, m ()), ApplyAB f x (m ())) => ApplyAB (HSeq f) pair fx 

data HFlip Source

Constructors

HFlip 

Instances

((~) * f1 (a -> b -> c), (~) * f2 (b -> a -> c)) => ApplyAB HFlip f1 f2 

Proxy

data Label l Source

A special Proxy for record labels, polykinded

Constructors

Label 

Instances

(~) k x x' => ToSym * k (Label k x) x'

for Data.HList.Label6 labels

IsKeyFN * (Label Symbol s -> a -> b) True

labels that impose no restriction on the type of the (single) argument which follows

>>> let testF (_ :: Label "a") (a :: Int) () = a+1
>>> kw (hBuild testF) (Label :: Label "a") 5 ()
6
Show desc => Show (Label * (Lbl k * x ns desc)) 
type LabelsOf ((:) * (Label * l) r) = (:) * l (LabelsOf r) 

class ShowLabel l where Source

Methods

showLabel :: Label l -> String Source

Instances

KnownSymbol x => ShowLabel Symbol x 
Show desc => ShowLabel * (Lbl k * x ns desc)

Equality on labels (descriptions are ignored) Use generic instance

Show label

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

type family HAnd t1 t2 :: Bool Source

Instances

type HAnd False t = False 
type HAnd True t = t 

hAnd :: Proxy t1 -> Proxy t2 -> Proxy (HAnd t1 t2) Source

demote to values

Disjunction

type family HOr t1 t2 :: Bool Source

Instances

type HOr False t = t 
type HOr True t = True 

hOr :: Proxy t1 -> Proxy t2 -> Proxy (HOr t1 t2) Source

demote to values

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

class HCond t x y z | t x y -> z where Source

Methods

hCond :: Proxy t -> x -> y -> z Source

Instances

HCond False x y y 
HCond True x y x 

Boolean equivalence

type family HBoolEQ t1 t2 :: Bool Source

Instances

Naturals

data HNat Source

The data type to be lifted to the type level

Constructors

HZero 
HSucc HNat 

Instances

HEq HNat HZero HZero True 
HEq HNat HZero (HSucc n) False 
HEq HNat (HSucc n) HZero False 
HEq HNat n n' b => HEq HNat (HSucc n) (HSucc n') b 
HTypes2HNats [*] [*] ([] *) l ([] HNat)

And lift to the list of types

(HType2HNat k [*] e l n, HTypes2HNats [k] [*] es l ns) => HTypes2HNats [k] [*] ((:) k e es) l ((:) HNat n ns) 
HLookupByHNat n l => Apply (FHLookupByHNat l) (Proxy HNat n) 
HNat2Integral n => Show (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) 
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) 

hSucc :: Proxy (n :: HNat) -> Proxy (HSucc n) Source

type family HNatEq t1 t2 :: Bool Source

Equality on natural numbers (eventually to be subsumed by the universal polykinded HEq)

Instances

type HNatEq HZero HZero = True 
type HNatEq HZero (HSucc n) = False 
type HNatEq (HSucc n) HZero = False 
type HNatEq (HSucc n) (HSucc n') = HNatEq n n' 

type family HLt x y :: Bool Source

Less than

Instances

type HLt HZero HZero = False 
type HLt HZero (HSucc n) = True 
type HLt (HSucc n) HZero = False 
type HLt (HSucc n) (HSucc n') = HLt n n' 

hLt :: Proxy x -> Proxy y -> Proxy (HLt x y) Source

Maybies

We cannot use lifted Maybe since the latter are not populated

data HNothing Source

Constructors

HNothing 

Instances

Show HNothing 
HUnfold' p HNothing 
FromHJust l => FromHJust ((:) * HNothing l) 
type HUnfoldR p HNothing = [] * 
type FromHJustR ((:) * HNothing l) = FromHJustR l 

newtype HJust x Source

Constructors

HJust x 

Instances

(Apply p s, HUnfold' p (ApplyR p s)) => HUnfold' p (HJust (e, s)) 
Show x => Show (HJust x) 
(~) * hJustA (HJust a) => ApplyAB (HJust t) a hJustA

HJust () is a placeholder for a function that applies the HJust constructor

FromHJust l => FromHJust ((:) * (HJust e) l) 
ToHJust l l' => ToHJust ((:) * e l) ((:) * (HJust e) l') 
type HUnfoldR p (HJust (e, s)) = (:) * e (HUnfold 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.

Instances

(~) Bool False b => HEq k x y b 
HEq k x x True 
HEq HNat HZero HZero True 
HEq HNat HZero (HSucc n) False 
HEq HNat (HSucc n) HZero False 
HEq HNat n n' b => HEq HNat (HSucc n) (HSucc n') b 
HEq [k] ([] k) ([] k) True 
HEq [k] ([] k) ((:) k e l) False 
HEq [k] ((:) k e l) ([] k) False 
(HEq k e1 e2 b1, HEq [k] l1 l2 b2, (~) Bool br (HAnd b1 b2)) => HEq [k] ((:) k e1 l1) ((:) k e2 l2) br 

hEq :: HEq x y b => x -> y -> Proxy b Source

Staged equality

Type-safe cast -- no longer need. We use a a ~ b

Error messages

class Fail x Source

A class without instances for explicit failure

module Data.Proxy