Safe Haskell | None |
---|---|
Language | Haskell2010 |
The HList library
(C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
Type-indexed products. The public interface is described in CommonMain#TIP
- module Data.HList.TIPtuple
- newtype TIP l = TIP {}
- mkTIP :: HTypeIndexed l => HList l -> TIP l
- emptyTIP :: TIP []
- class (HAllTaggedEq l, HRLabelSet l) => HTypeIndexed l
- class HAllTaggedEq l
- onRecord :: (HAllTaggedEq l, HLabelSet [*] (LabelsOf l), HAllTaggedLV l) => (Record r -> Record l) -> TIP r -> TIP l
- tipyUpdate :: (HUpdateAtLabel * record v v r r, SameLength' * * r r) => v -> record r -> record r
- tipyProject :: (HAllTaggedEq l, HLabelSet [*] (LabelsOf l), H2ProjectByLabels ls r l b, HAllTaggedLV l) => proxy ls -> TIP r -> TIP l
- tipyLens' :: (HAllTaggedEq t, HLabelSet [*] (LabelsOf t), HasField * b (Record t) b, HUpdateAtLabel2 * b b t t, SameLength' * * t t, SameLabels [*] [*] t t, HAllTaggedLV t, Functor f) => (b -> f b) -> TIP t -> f (TIP t)
- tipyLens :: (HAllTaggedEq t, HAllTaggedEq s, HLabelSet [*] (LabelsOf t), HLabelSet [*] (LabelsOf s), HasField * b (Record t) b, HasField * b (Record s) b, HUpdateAtLabel2 * b b t s, HUpdateAtLabel2 * b b s t, SameLength' * * t s, SameLength' * * s t, SameLabels [*] [*] s t, HAllTaggedLV t, HAllTaggedLV s, Functor f) => (b -> f b) -> TIP s -> f (TIP t)
- tipyProject2 :: (HAllTaggedEq l1, HAllTaggedEq l, HLabelSet [*] (LabelsOf l), HLabelSet [*] (LabelsOf l1), H2ProjectByLabels ls r l l1, HAllTaggedLV l1, HAllTaggedLV l) => proxy ls -> TIP r -> (TIP l, TIP l1)
- class SameLength a ta => TagUntagFD a ta | a -> ta, ta -> a where
- type TagUntag xs = TagUntagFD xs (TagR xs)
- type UntagTag xs = TagUntagFD (UntagR xs) xs
- type family TagR a :: [*]
- type family UntagR ta :: [*]
- type family Untag1 x :: *
- tipHList :: (TagUntagFD a1 l, TagUntagFD a ta, Profunctor p, Functor f) => p (HList a) (f (HList a1)) -> p (TIP ta) (f (TIP l))
- tipHList' :: (TagUntagFD a ta, Profunctor p, Functor f) => p (HList a) (f (HList a)) -> p (TIP ta) (f (TIP ta))
- tipRecord :: (Profunctor p, Functor f) => p (Record r) (f (Record l)) -> p (TIP r) (f (TIP l))
- tipRecord' :: (Profunctor p, Functor f) => p (Record r) (f (Record r)) -> p (TIP r) (f (TIP r))
- hZipTIP :: (TagUntagFD y ta1, TagUntagFD x ta, TagUntagFD a l, HZipList x y a) => TIP ta -> TIP ta1 -> TIP l
- hUnzipTIP :: (HAllTaggedEq l2, HAllTaggedEq l1, TagUntagFD a1 l2, TagUntagFD a l1, TagUntagFD l ta, HLabelSet [*] (LabelsOf l1), HLabelSet [*] (LabelsOf l2), HZipList a a1 l, HAllTaggedLV l2, HAllTaggedLV l1) => TIP ta -> (TIP l1, TIP l2)
- class TransTIP op db where
- class TransTIP1 b n op db where
- class TransTIP2 b arg op db where
- class Monad m => TransTIPM m op db where
- class Monad m => TransTIPM1 b n m op db where
- class TransTIPM2 b m arg op db where
Documentation
module Data.HList.TIPtuple
The newtype for type-indexed products
TIPs are like Record
, except element "i" of the list "l"
has type Tagged e_i e_i
TypeIndexed Record TIP | |
(HZipList (UntagR x) (UntagR y) (UntagR xy), UntagTag x, UntagTag y, UntagTag xy, SameLengths * ((:) [*] x ((:) [*] y ((:) [*] xy ([] [*])))), HTypeIndexed x, HTypeIndexed y, HUnzip TIP x y xy) => HZip TIP x y xy | |
(HZipList (UntagR x) (UntagR y) (UntagR xy), UntagTag x, UntagTag y, UntagTag xy, HTypeIndexed x, HTypeIndexed y, SameLengths * ((:) [*] x ((:) [*] y ((:) [*] xy ([] [*]))))) => HUnzip TIP x y xy | |
(HDeleteAtLabel k Record e v v', HTypeIndexed v') => HDeleteAtLabel k TIP e v v' | |
(HUpdateAtLabel * Record e' e r r', HTypeIndexed r', (~) * e e') => HUpdateAtLabel * TIP e' e r r' | |
LabelableTIPCxt x s t a b => Labelable * x TIP s t a b | make a
|
((~) * e e', HasField * e (Record l) e') => HasField * e (TIP l) e' | |
(HOccurs e (TIP l1), SubType * * (TIP l1) (TIP l2)) => SubType * * (TIP l1) (TIP ((:) * e l2)) | |
SubType * * (TIP l) (TIP ([] *)) | Subtyping for TIPs |
HasField * e (Record ((:) * x ((:) * y l))) e => HOccurs e (TIP ((:) * x ((:) * y l))) | |
(~) * tee (Tagged * e e) => HOccurs e (TIP ((:) * tee ([] *))) | 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. |
(HRLabelSet ((:) * (Tagged * e e) l), HTypeIndexed l) => HExtend e (TIP l) | |
Bounded (HList r) => Bounded (TIP r) | |
Eq (HList a) => Eq (TIP a) | |
(TypeablePolyK [*] xs, Typeable * (HList xs), Data (HList xs)) => Data (TIP xs) | |
Ord (HList r) => Ord (TIP r) | |
HMapOut (HComp HShow HUntag) l String => Show (TIP l) | |
Ix (HList r) => Ix (TIP r) | |
Monoid (HList a) => Monoid (TIP a) | |
(HAppend (HList l) (HList l'), HTypeIndexed (HAppendListR * l l')) => HAppend (TIP l) (TIP l') | |
Typeable ([*] -> *) TIP | |
type LabelableTy TIP = LabelableLens | |
type HExtendR e (TIP l) = TIP ((:) * (Tagged * e e) l) | |
type HAppendR * (TIP l) (TIP l') = TIP (HAppendListR * l l') |
mkTIP :: HTypeIndexed l => HList l -> TIP l Source
Type-indexed type sequences
class (HAllTaggedEq l, HRLabelSet l) => HTypeIndexed l Source
this constraint ensures that a TIP created by mkTIP
has no
duplicates
(HAllTaggedEq l, HRLabelSet l) => HTypeIndexed l |
class HAllTaggedEq l Source
HAllTaggedEq ([] *) | |
(HAllTaggedEq l, (~) * tee (Tagged k e e')) => HAllTaggedEq ((:) * tee l) |
Shielding type-indexed operations
The absence of signatures is deliberate! They all must be inferred.
onRecord :: (HAllTaggedEq l, HLabelSet [*] (LabelsOf l), HAllTaggedLV l) => (Record r -> Record l) -> TIP r -> TIP l Source
tipyUpdate :: (HUpdateAtLabel * record v v r r, SameLength' * * r r) => v -> record r -> record r Source
tipyProject :: (HAllTaggedEq l, HLabelSet [*] (LabelsOf l), H2ProjectByLabels ls r l b, HAllTaggedLV l) => proxy ls -> TIP r -> TIP l Source
Use Labels
to specify the first argument
tipyLens' :: (HAllTaggedEq t, HLabelSet [*] (LabelsOf t), HasField * b (Record t) b, HUpdateAtLabel2 * b b t t, SameLength' * * t t, SameLabels [*] [*] t t, HAllTaggedLV t, Functor f) => (b -> f b) -> TIP t -> f (TIP t) Source
provides a Lens' (TIP s) a
. hLens'
:: Label a -> Lens' (TIP s) a
is another option.
tipyLens :: (HAllTaggedEq t, HAllTaggedEq s, HLabelSet [*] (LabelsOf t), HLabelSet [*] (LabelsOf s), HasField * b (Record t) b, HasField * b (Record s) b, HUpdateAtLabel2 * b b t s, HUpdateAtLabel2 * b b s t, SameLength' * * t s, SameLength' * * s t, SameLabels [*] [*] s t, HAllTaggedLV t, HAllTaggedLV s, Functor f) => (b -> f b) -> TIP s -> f (TIP t) 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 :: (HAllTaggedEq l1, HAllTaggedEq l, HLabelSet [*] (LabelsOf l), HLabelSet [*] (LabelsOf l1), H2ProjectByLabels ls r l l1, HAllTaggedLV l1, HAllTaggedLV l) => proxy ls -> TIP r -> (TIP l, TIP l1) 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 xHCons
hTagSelf xs hUntagSelf (HCons (Tagged x) xs) = xHCons
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 () ()]
TagUntagFD ([] *) ([] *) | |
(TagUntagFD xs ys, (~) * txx (Tagged * x x)) => TagUntagFD ((:) * x xs) ((:) * txx ys) |
type TagUntag xs = TagUntagFD xs (TagR xs) Source
type UntagTag 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:
tipHList :: (TagUntagFD a1 l, TagUntagFD a ta, Profunctor p, Functor f) => p (HList a) (f (HList a1)) -> p (TIP ta) (f (TIP l)) Source
Iso (TIP (TagR a)) (TIP (TagR b)) (HList a) (HList b)
tipHList' :: (TagUntagFD a ta, Profunctor p, Functor f) => p (HList a) (f (HList a)) -> p (TIP ta) (f (TIP ta)) Source
Iso' (TIP (TagR s)) (HList a)
conversion to and from Record
tipRecord :: (Profunctor p, Functor f) => 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 r) (f (Record r)) -> p (TIP r) (f (TIP r)) Source
Iso' (TIP (TagR s)) (Record a)
Zip
hZipTIP :: (TagUntagFD y ta1, TagUntagFD x ta, TagUntagFD a l, HZipList x y a) => TIP ta -> TIP ta1 -> TIP l Source
specialization of hZip
hUnzipTIP :: (HAllTaggedEq l2, HAllTaggedEq l1, TagUntagFD a1 l2, TagUntagFD a l1, TagUntagFD l ta, HLabelSet [*] (LabelsOf l1), HLabelSet [*] (LabelsOf l2), HZipList a a1 l, HAllTaggedLV l2, HAllTaggedLV l1) => TIP ta -> (TIP l1, TIP l2) 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
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.
class Monad m => TransTIPM1 b n m op db where Source
(Fail ((,,) * Symbol [*]) ((,,) * Symbol [*] (TypeNotFound * op) "in TIP" db), Monad m) => TransTIPM1 False HZero m op db | |
(Monad m, (~) (* -> *) m m', HTPupdateAtLabel * TIP op op db) => TransTIPM1 True n m (m' op) db | |
(Monad m, HMember * (Tagged * arg arg) db b, TransTIPM2 b m arg op db) => TransTIPM1 False (HSucc n) m (arg -> op) db |
class TransTIPM2 b m arg op db where Source
Fail ((,,) * Symbol [*]) ((,,) * Symbol [*] (TypeNotFound * op) "in TIP" db) => TransTIPM2 False m arg op db | |
(HOccurs arg (TIP db), TransTIPM m op db) => TransTIPM2 True m arg op db |
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 Animal
>>>
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))) ...