HList-0.5.0.0: Heterogeneous lists

Safe HaskellNone
LanguageHaskell2010

Data.HList.TIP

Contents

Description

The HList library

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

Type-indexed products. The public interface is described in CommonMain#TIP

Synopsis

Documentation

The newtype for type-indexed products

newtype TIP (l :: [*]) Source #

TIPs are like Record, except element "i" of the list "l" has type Tagged e_i e_i

Constructors

TIP 

Fields

Instances

TypeIndexed Record TIP Source # 

Methods

typeIndexed :: (TypeIndexedCxt s t a b, Profunctor p, Functor f) => p (TIP (TagR a)) (f (TIP (TagR b))) -> p (Record s) (f (Record t)) Source #

(HUnzip TIP x y xy, HZipList xL yL xyL, (~) * lty (HList xL -> HList yL -> HList xyL), Coercible * lty (TIP x -> TIP y -> TIP xy), (~) [*] (UntagR x) xL, (~) [*] (UntagR y) yL, (~) [*] (UntagR xy) xyL, UntagTag x, UntagTag y, UntagTag xy) => HZip TIP x y xy Source # 

Methods

hZip :: TIP x -> TIP y -> TIP xy Source #

(HZipList xL yL xyL, (~) * lty (HList xyL -> (HList xL, HList yL)), Coercible * lty (TIP xy -> (TIP x, TIP y)), (~) [*] (UntagR x) xL, (~) [*] (TagR xL) x, (~) [*] (UntagR y) yL, (~) [*] (TagR yL) y, (~) [*] (UntagR xy) xyL, (~) [*] (TagR xyL) xy, SameLengths * ((:) [*] x ((:) [*] y ((:) [*] xy ([] [*])))), UntagTag x, UntagTag y, UntagTag xy) => HUnzip TIP x y xy Source # 

Methods

hUnzip :: TIP xy -> (TIP x, TIP y) Source #

(HDeleteAtLabel k Record e v v', HTypeIndexed v') => HDeleteAtLabel k TIP e v v' Source # 

Methods

hDeleteAtLabel :: Label TIP v -> e v' -> e v' Source #

(HUpdateAtLabel * Record e' e r r', HTypeIndexed r', (~) * e e') => HUpdateAtLabel * TIP e' e r r' Source # 

Methods

hUpdateAtLabel :: Label TIP e -> r -> e' r' -> e' r' Source #

LabelableTIPCxt k x s t a b => Labelable k x TIP s t a b Source #

make a Lens' (TIP s) a.

tipyLens provides a Lens (TIP s) (TIP t) a b, which tends to need too many type annotations to be practical

Associated Types

type LabelableTy (s :: [*] -> *) :: LabeledOpticType Source #

Methods

hLens' :: Label x TIP -> LabeledOptic x TIP s t a b b Source #

HasField * e (Record ((:) * x ((:) * y l))) e => HOccurs e (TIP ((:) * x ((:) * y l))) Source # 

Methods

hOccurs :: TIP ((* ': x) ((* ': y) l)) -> e Source #

(~) * tee (Tagged * e e) => HOccurs e (TIP ((:) * tee ([] *))) Source #

One occurrence and nothing is left

This variation provides an extra feature for singleton lists. That is, the result type is unified with the element in the list. Hence the explicit provision of a result type can be omitted.

Methods

hOccurs :: TIP ((* ': tee) [*]) -> e Source #

(HRLabelSet ((:) * (Tagged * e e) l), HTypeIndexed l) => HExtend e (TIP l) Source # 

Associated Types

type HExtendR e (TIP l) :: * Source #

Methods

(.*.) :: e -> TIP l -> HExtendR e (TIP l) Source #

Bounded (HList r) => Bounded (TIP r) Source # 

Methods

minBound :: TIP r #

maxBound :: TIP r #

Eq (HList a) => Eq (TIP a) Source # 

Methods

(==) :: TIP a -> TIP a -> Bool #

(/=) :: TIP a -> TIP a -> Bool #

Ord (HList r) => Ord (TIP r) Source # 

Methods

compare :: TIP r -> TIP r -> Ordering #

(<) :: TIP r -> TIP r -> Bool #

(<=) :: TIP r -> TIP r -> Bool #

(>) :: TIP r -> TIP r -> Bool #

(>=) :: TIP r -> TIP r -> Bool #

max :: TIP r -> TIP r -> TIP r #

min :: TIP r -> TIP r -> TIP r #

HMapOut (HComp HShow HUntag) l String => Show (TIP l) Source # 

Methods

showsPrec :: Int -> TIP l -> ShowS #

show :: TIP l -> String #

showList :: [TIP l] -> ShowS #

Ix (HList r) => Ix (TIP r) Source # 

Methods

range :: (TIP r, TIP r) -> [TIP r] #

index :: (TIP r, TIP r) -> TIP r -> Int #

unsafeIndex :: (TIP r, TIP r) -> TIP r -> Int

inRange :: (TIP r, TIP r) -> TIP r -> Bool #

rangeSize :: (TIP r, TIP r) -> Int #

unsafeRangeSize :: (TIP r, TIP r) -> Int

Semigroup (HList a) => Semigroup (TIP a) Source # 

Methods

(<>) :: TIP a -> TIP a -> TIP a #

sconcat :: NonEmpty (TIP a) -> TIP a #

stimes :: Integral b => b -> TIP a -> TIP a #

Monoid (HList a) => Monoid (TIP a) Source # 

Methods

mempty :: TIP a #

mappend :: TIP a -> TIP a -> TIP a #

mconcat :: [TIP a] -> TIP a #

((~) * e e', HasField * e (Record l) e') => HasField * e (TIP l) e' Source # 

Methods

hLookupByLabel :: Label e (TIP l) -> e' -> v Source #

(HAppend (HList l) (HList l'), HTypeIndexed (HAppendListR * l l')) => HAppend (TIP l) (TIP l') Source # 

Methods

hAppend :: TIP l -> TIP l' -> HAppendR * (TIP l) (TIP l') Source #

(HOccurs e (TIP l1), SubType * * (TIP l1) (TIP l2)) => SubType * * (TIP l1) (TIP ((:) * e l2)) Source # 
SubType * * (TIP l) (TIP ([] *)) Source #

Subtyping for TIPs

type LabelableTy TIP Source # 
type HExtendR e (TIP l) Source # 
type HExtendR e (TIP l) = TIP ((:) * (Tagged * e e) l)
type HAppendR * (TIP l) (TIP l') Source # 
type HAppendR * (TIP l) (TIP l') = TIP (HAppendListR * l l')

Type-indexed type sequences

class (HAllTaggedEq l, HRLabelSet l) => HTypeIndexed (l :: [*]) Source #

this constraint ensures that a TIP created by mkTIP has no duplicates

Instances

class HAllTaggedEq (l :: [*]) Source #

Instances

HAllTaggedEq ([] *) Source # 
(HAllTaggedEq l, (~) * tee (Tagged k e e')) => HAllTaggedEq ((:) * tee l) Source # 

Shielding type-indexed operations

The absence of signatures is deliberate! They all must be inferred.

onRecord :: (HAllTaggedLV l, HLabelSet [*] (LabelsOf l), HAllTaggedEq l) => (Record r -> Record l) -> TIP r -> TIP l Source #

tipyUpdate :: (SameLength' * * r r, HUpdateAtLabel * record v v r r) => v -> record r -> record r Source #

tipyProject :: (H2ProjectByLabels ls t l b, HAllTaggedEq l, HLabelSet [*] (LabelsOf l), HAllTaggedLV l) => proxy ls -> TIP t -> TIP l Source #

Use Labels to specify the first argument

tipyLens' :: (Functor f, SameLabels [*] [*] t t, SameLength' * * t t, HAllTaggedLV t, HLabelSet [*] (LabelsOf t), HAllTaggedEq t, HUpdateAtLabel2 * a a t t, HasField * a (Record t) a) => (a -> f a) -> TIP t -> f (TIP t) Source #

provides a Lens' (TIP s) a. hLens' :: Label a -> Lens' (TIP s) a is another option.

tipyLens :: (Functor f, HAppendList l1 ((:) * (Tagged * a2 a2) xs2), HAllTaggedLV (HAppendListR * l1 ((:) * (Tagged * a2 a2) xs2)), HLabelSet [*] (LabelsOf (HAppendListR * l1 ((:) * (Tagged * a2 a2) xs2))), HAllTaggedEq (HAppendListR * l1 ((:) * (Tagged * a2 a2) xs2)), HFind2 * b (Label * a1) (LabelsOf xs1) ((:) * (Label * x) (LabelsOf xs1)) n, HEq * (Label * a1) (Label * x) b, HLengthEq2 HNat l1 n, HLengthEq1 HNat l1 n, SameLength' * * (HReplicateR * n ()) l1, HAppendList1 * l1 ((:) * (Tagged * a1 a1) xs2) ((:) * (Tagged * x x) xs1), HSplitAt1 ([] *) n ((:) * (Tagged * x x) xs1) l1 ((:) * (Tagged * a1 a1) xs2)) => (a1 -> f a2) -> TIP ((:) * (Tagged * x x) xs1) -> f (TIP (HAppendListR * l1 ((:) * (Tagged * a2 a2) xs2))) Source #

provides a Lens (TIP s) (TIP t) a b

When using set (also known as .~), tipyLens' can address the ambiguity as to which field "a" should actually be updated.

tipyProject2 :: (HAllTaggedLV l2, HAllTaggedLV l1, HLabelSet [*] (LabelsOf l2), HLabelSet [*] (LabelsOf l1), HAllTaggedEq l2, HAllTaggedEq l1, H2ProjectByLabels ls r l1 l2) => proxy ls -> TIP r -> (TIP l1, TIP l2) Source #

The same as tipyProject, except also return the types not requested in the proxy argument

conversion to and from HList

class SameLength a ta => TagUntagFD a ta | a -> ta, ta -> a where Source #

TagR can also be used to avoid redundancy when defining types for TIC and TIP.

 type XShort = TagR [A,B,C,D]
 type XLong = [Tagged A A, Tagged B B, Tagged C C, Tagged D D]

an equivalent FD version, which is slightly better with respect to simplifying types containing type variables (in ghc-7.8 and 7.6): http://stackoverflow.com/questions/24110410/

With ghc-7.10 (http://ghc.haskell.org/trac/ghc/ticket/10009) the FD version is superior to the TF version:

class (UntagR (TagR a) ~ a) => TagUntag a where
    type TagR a :: [*]
    hTagSelf :: HList a -> HList (TagR a)
    hUntagSelf :: HList (TagR a) -> HList a

instance TagUntag '[] where
    type TagR '[] = '[]
    hTagSelf _ = HNil
    hUntagSelf _ = HNil

instance TagUntag xs => TagUntag (x ': xs) where
    type TagR (x ': xs) = Tagged x x ': TagR xs
    hTagSelf (HCons x xs) = Tagged x HCons hTagSelf xs
    hUntagSelf (HCons (Tagged x) xs) = x HCons hUntagSelf xs

type family UntagR (xs :: [*]) :: [*]
type instance UntagR '[] = '[]
type instance UntagR (x ': xs) = Untag1 x ': UntagR xs

Length information should flow backwards

>>> let len2 x = x `asTypeOf` (undefined :: HList '[a,b])
>>> let f = len2 $ hTagSelf (hReplicate Proxy ())
>>> :t f
f :: HList '[Tagged () (), Tagged () ()]

Minimal complete definition

hTagSelf, hUntagSelf

Methods

hTagSelf :: HList a -> HList ta Source #

hUntagSelf :: HList ta -> HList a Source #

Instances

TagUntagFD ([] *) ([] *) Source # 

Methods

hTagSelf :: HList [*] -> HList [*] Source #

hUntagSelf :: HList [*] -> HList [*] Source #

(TagUntagFD xs ys, (~) * txx (Tagged * x x)) => TagUntagFD ((:) * x xs) ((:) * txx ys) Source # 

Methods

hTagSelf :: HList ((* ': x) xs) -> HList ((* ': txx) ys) Source #

hUntagSelf :: HList ((* ': txx) ys) -> HList ((* ': x) xs) Source #

type TagUntag xs = TagUntagFD xs (TagR xs) Source #

type UntagTag xs = (TagR (UntagR xs) ~ xs, TagUntagFD (UntagR xs) xs) Source #

Sometimes the type variables available have TagR already applied (ie the lists have elements like Tagged X X). Then this abbreviation is useful:

type family TagR (a :: [*]) :: [*] Source #

Instances

type TagR ([] *) Source # 
type TagR ([] *) = [] *
type TagR ((:) * x xs) Source # 
type TagR ((:) * x xs) = (:) * (Tagged * x x) (TagR xs)

type family UntagR (ta :: [*]) :: [*] Source #

Instances

type UntagR ([] *) Source # 
type UntagR ([] *) = [] *
type UntagR ((:) * (Tagged * y y) ys) Source # 
type UntagR ((:) * (Tagged * y y) ys) = (:) * y (UntagR ys)

type family Untag1 (x :: *) :: * Source #

Instances

type Untag1 (Tagged k1 k2 x) Source # 
type Untag1 (Tagged k1 k2 x) = x

tipHList :: (TagUntagFD a2 l, TagUntagFD a1 ta, Functor f, Profunctor p) => p (HList a1) (f (HList a2)) -> p (TIP ta) (f (TIP l)) Source #

Iso (TIP (TagR a)) (TIP (TagR b)) (HList a) (HList b)

tipHList' :: (Profunctor p, Functor f, TagUntagFD a l) => p (HList a) (f (HList a)) -> p (TIP l) (f (TIP l)) Source #

Iso' (TIP (TagR s)) (HList a)

conversion to and from Record

tipRecord :: (Functor f, Profunctor p) => p (Record r) (f (Record l)) -> p (TIP r) (f (TIP l)) Source #

Iso (TIP s) (TIP t) (Record s) (Record t)

typeIndexed may be more appropriate

tipRecord' :: (Profunctor p, Functor f) => p (Record l) (f (Record l)) -> p (TIP l) (f (TIP l)) Source #

Iso' (TIP (TagR s)) (Record a)

Zip

hZipTIP :: (TagUntagFD y ta2, TagUntagFD x ta1, TagUntagFD a l, HZipList x y a) => TIP ta1 -> TIP ta2 -> TIP l Source #

specialization of hZip

hUnzipTIP :: (TagUntagFD a2 l3, TagUntagFD a1 l2, TagUntagFD l1 ta, HAllTaggedLV l3, HAllTaggedLV l2, HLabelSet [*] (LabelsOf l3), HLabelSet [*] (LabelsOf l2), HAllTaggedEq l3, HAllTaggedEq l2, HZipList a1 a2 l1) => TIP ta -> (TIP l2, TIP l3) Source #

specialization of hUnzip

TIP Transform

class TransTIP op db where Source #

Transforming a TIP: applying to a TIP a (polyvariadic) function that takes arguments from a TIP and updates the TIP with the result.

In more detail: we have a typed-indexed collection TIP and we would like to apply a transformation function to it, whose argument types and the result type are all in the TIP. The function should locate its arguments based on their types, and update the TIP with the result. The function may have any number of arguments, including zero; the order of arguments should not matter.

The problem was posed by Andrew U. Frank on Haskell-Cafe, Sep 10, 2009. http://www.haskell.org/pipermail/haskell-cafe/2009-September/066217.html The problem is an interesting variation of the keyword argument problem.

Examples can be found in examples/TIPTransform.hs and examples/TIPTransformM.hs

Minimal complete definition

ttip

Methods

ttip :: op -> TIP db -> TIP db Source #

Instances

(HMember * (Tagged * op op) db b, Arity op n, TransTIP1 b n op db) => TransTIP op db Source # 

Methods

ttip :: op -> TIP db -> TIP db Source #

class TransTIP1 (b :: Bool) (n :: HNat) op db where Source #

Minimal complete definition

ttip1

Methods

ttip1 :: Proxy b -> Proxy n -> op -> TIP db -> TIP db Source #

Instances

Fail ErrorMessage (FieldNotFound * * notfun (TIP db)) => TransTIP1 False HZero notfun db Source # 

Methods

ttip1 :: Proxy Bool False -> Proxy HNat HZero -> notfun -> TIP db -> TIP db Source #

HTPupdateAtLabel * TIP op op db => TransTIP1 True n op db Source # 

Methods

ttip1 :: Proxy Bool True -> Proxy HNat n -> op -> TIP db -> TIP db Source #

(HMember * (Tagged * arg arg) db b, TransTIP2 b arg op db) => TransTIP1 False (HSucc n) (arg -> op) db Source # 

Methods

ttip1 :: Proxy Bool False -> Proxy HNat (HSucc n) -> (arg -> op) -> TIP db -> TIP db Source #

class TransTIP2 (b :: Bool) arg op db where Source #

Minimal complete definition

ttip2

Methods

ttip2 :: Proxy b -> (arg -> op) -> TIP db -> TIP db Source #

Instances

Fail ErrorMessage (FieldNotFound * * arg (TIP db)) => TransTIP2 False arg op db Source # 

Methods

ttip2 :: Proxy Bool False -> (arg -> op) -> TIP db -> TIP db Source #

(HOccurs arg (TIP db), TransTIP op db) => TransTIP2 True arg op db Source # 

Methods

ttip2 :: Proxy Bool True -> (arg -> op) -> TIP db -> TIP db Source #

Monadic version

class Monad m => TransTIPM m op db where Source #

In March 2010, Andrew Frank extended the problem for monadic operations. This is the monadic version of TIPTransform.hs in the present directory.

This is the TF implementation. When specifying the operation to perform over a TIP, we can leave it polymorphic over the monad. The type checker will instantiate the monad based on the context.

Minimal complete definition

ttipM

Methods

ttipM :: op -> TIP db -> m (TIP db) Source #

Instances

(Monad m, HMember * (Tagged * op op) db b, Arity (m' op) n, TransTIPM1 b n m (m' op) db) => TransTIPM m (m' op) db Source # 

Methods

ttipM :: m' op -> TIP db -> m (TIP db) Source #

class Monad m => TransTIPM1 (b :: Bool) (n :: HNat) m op db where Source #

Minimal complete definition

ttipM1

Methods

ttipM1 :: Proxy b -> Proxy n -> op -> TIP db -> m (TIP db) Source #

Instances

(Fail ErrorMessage (FieldNotFound * * op (TIP db)), Monad m) => TransTIPM1 False HZero m op db Source # 

Methods

ttipM1 :: Proxy Bool False -> Proxy HNat HZero -> op -> TIP db -> m (TIP db) Source #

(Monad m, (~) (* -> *) m m', HTPupdateAtLabel * TIP op op db) => TransTIPM1 True n m (m' op) db Source # 

Methods

ttipM1 :: Proxy Bool True -> Proxy HNat n -> m' op -> TIP db -> m (TIP db) Source #

(Monad m, HMember * (Tagged * arg arg) db b, TransTIPM2 b m arg op db) => TransTIPM1 False (HSucc n) m (arg -> op) db Source # 

Methods

ttipM1 :: Proxy Bool False -> Proxy HNat (HSucc n) -> (arg -> op) -> TIP db -> m (TIP db) Source #

class TransTIPM2 (b :: Bool) m arg op db where Source #

Minimal complete definition

ttipM2

Methods

ttipM2 :: Proxy b -> (arg -> op) -> TIP db -> m (TIP db) Source #

Instances

Fail ErrorMessage (FieldNotFound * * op (TIP db)) => TransTIPM2 False m arg op db Source # 

Methods

ttipM2 :: Proxy Bool False -> (arg -> op) -> TIP db -> m (TIP db) Source #

(HOccurs arg (TIP db), TransTIPM m op db) => TransTIPM2 True m arg op db Source # 

Methods

ttipM2 :: Proxy Bool True -> (arg -> op) -> TIP db -> m (TIP db) Source #

Sample code

Assume
>>> import Data.HList.TypeEqO
>>> import Data.HList.FakePrelude
>>> import Data.HList.HOccurs
>>> :{
newtype Key    = Key Integer deriving (Show,Eq,Ord)
newtype Name   = Name String deriving (Show,Eq)
data Breed     = Cow | Sheep deriving (Show,Eq)
newtype Price  = Price Float deriving (Show,Eq,Ord)
data Disease   = BSE | FM deriving (Show,Eq)
type Animal =  TagR '[Key,Name,Breed,Price]
:}
>>> :{
let myTipyCow :: TIP Animal -- optional
    myTipyCow = Key 42 .*.  Name "Angus" .*.  Cow .*.  Price 75.5 .*. emptyTIP
    animalKey :: (HOccurs Key l, SubType l (TIP Animal)) => l -> Key
    animalKey = hOccurs
:}
Session log
>>> :t myTipyCow
myTipyCow
  :: TIP
       '[Tagged Key Key, Tagged Name Name, Tagged Breed Breed,
         Tagged Price Price]
>>> hOccurs myTipyCow :: Breed
Cow
>>> BSE .*. myTipyCow
TIPH[BSE,Key 42,Name "Angus",Cow,Price 75.5]
>>> Sheep .*. hDeleteAtLabel (Label::Label Breed) myTipyCow
TIPH[Sheep,Key 42,Name "Angus",Price 75.5]
>>> tipyUpdate Sheep myTipyCow
TIPH[Key 42,Name "Angus",Sheep,Price 75.5]
>>> tipyProject2 (Proxy :: Labels '[Name,Price]) myTipyCow
(TIPH[Name "Angus",Price 75.5],TIPH[Key 42,Cow])
>>> tipyProject (Proxy :: Labels '[Name,Price]) myTipyCow
TIPH[Name "Angus",Price 75.5]

Don't bother repeating the type error:

>>> Sheep .*. myTipyCow
...
...No instance for (Fail (DuplicatedLabel (Label Breed)))
...