diff --git a/Data/HList/GhcRecord.hs b/Data/HList/GhcRecord.hs
--- a/Data/HList/GhcRecord.hs
+++ b/Data/HList/GhcRecord.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE PatternSignatures, ScopedTypeVariables, EmptyDataDecls,
-  FunctionalDependencies, FlexibleInstances, FlexibleContexts,
-  MultiParamTypeClasses, UndecidableInstances #-}
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+{-# LANGUAGE ScopedTypeVariables, EmptyDataDecls, FunctionalDependencies, 
+  MultiParamTypeClasses, UndecidableInstances, PatternSignatures,
+  FlexibleInstances, FlexibleContexts #-}
 
 {-
    The HList library
@@ -25,6 +26,7 @@
 
 -- A variation on update.
 -- Replace a proxy by a value of the proxied type.
+-- The signature is inferred
 hUnproxyLabel :: (HUpdateAtHNat n (LVPair l a) t l', HFind l ls n,
                                RecordLabels t ls,
                                HasField l t (Proxy a)) =>
@@ -140,7 +142,7 @@
 
 data NilLub
 nilLub :: NilLub
-nilLub = undefined :: NilLub
+nilLub = undefined
 
 class ConsLub h t l | h t -> l
  where
diff --git a/Data/HList/GhcSyntax.hs b/Data/HList/GhcSyntax.hs
--- a/Data/HList/GhcSyntax.hs
+++ b/Data/HList/GhcSyntax.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-
    (C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
@@ -33,6 +34,8 @@
 {-----------------------------------------------------------------------------}
 
 -- Convenience notation for records
+-- Many signatures are deliberately omitted. They should be inferred.
+-- There is no point of writing the same thing in terms and in types.
 
 infixr 4 :=:
 type l :=: v = LVPair l v
@@ -46,34 +49,18 @@
 r .!. l =  hLookupByLabel l r
 
 infixl 1 .-.
-(.-.) :: (H2ProjectByLabels (HCons e HNil) t t1 t2) => Record t -> e -> Record t2
 r .-. l =  hDeleteAtLabel l r
 
 infixl 1 .@.
-(.@.) :: (HUpdateAtHNat n (LVPair t t1) t2 l',
-         HFind t ls n,
-         RecordLabels t2 ls) =>
-        Record t2 -> LVPair t t1 -> Record l'
 r .@. f@(LVPair v) =  hUpdateAtLabel (labelLVPair f) v r
 
 infixr 1 .^.
-(.^.) :: (HasField t t2 (Proxy t1),
-         RecordLabels t2 ls,
-         HFind t ls n,
-         Data.HList.HArray.HUpdateAtHNat n (LVPair t t1) t2 l') =>
-         LVPair t t1 -> Record t2 -> Record l'
 f@(LVPair v) .^. r = hUnproxyLabel (labelLVPair f) v r
 
 infixr 1 .<.
-(.<.) :: (HasField t t2 t1,
-         RecordLabels t2 ls,
-         HFind t ls n,
-         HUpdateAtHNat n (LVPair t t1) t2 l') =>
-        LVPair t t1 -> Record t2 -> Record l'
 f@(LVPair v) .<. r = hTPupdateAtLabel (labelLVPair f) v r
 
 infixl 1 .<++.
-(.<++.) :: (HLeftUnion r r' r'') => r -> r' -> r''
 r .<++. r' = hLeftUnion r r'
 
 
@@ -86,11 +73,6 @@
 
 type e :+: l = HCons (Proxy e) l
 
-(.+.) :: ( HTypeIndexed l
-         , HTypeProxied l
-         , HOccursNot (Proxy e) l
-         )
-      => e -> TIP l -> TIP (HCons (Proxy e) l)
 e .+. r = hExtend (toProxy e) r
 
 
diff --git a/Data/HList/HArray.hs b/Data/HList/HArray.hs
--- a/Data/HList/HArray.hs
+++ b/Data/HList/HArray.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
 {-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
   FlexibleContexts, UndecidableInstances #-}
 {-
@@ -72,8 +73,9 @@
 {-----------------------------------------------------------------------------}
 
 -- Splitting an array according to indices
-hSplitByHNats :: (HSplitByHNats' ns l' l'1 l'', HMap (HAddTag HTrue) l l') =>
-                ns -> l -> (l'1, l'')
+-- Signature is inferred:
+-- hSplitByHNats :: (HSplitByHNats' ns l' l'1 l'', HMap (HAddTag HTrue) l l') =>
+--                ns -> l -> (l'1, l'')
 hSplitByHNats ns l = hSplitByHNats' ns (hFlag l)
 
 class HNats ns => HSplitByHNats' ns l l' l'' | ns l -> l' l''
diff --git a/Data/HList/Label1.hs b/Data/HList/Label1.hs
new file mode 100644
--- /dev/null
+++ b/Data/HList/Label1.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-}
+
+{-
+   The HList library
+
+   (C) 2004-2006, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
+
+   A model of label as needed for extensible records.
+
+   Record labels are simply type-level naturals.
+   This models is as simple and as portable as it could be.
+-}
+
+module Data.HList.Label1 where
+
+import Data.HList.FakePrelude
+import Data.HList.Record (ShowLabel(..))
+
+
+-- Labels are type-level naturals
+
+newtype Label x = Label x deriving Show
+
+
+-- Public constructors for labels
+
+label :: HNat n => n -> Label n
+label =  Label
+
+
+-- Construct the first label
+firstLabel :: Label HZero
+firstLabel = label hZero
+
+
+-- Construct the next label
+nextLabel ::( HNat t) => Label t -> Label (HSucc t)
+nextLabel (Label n) = label (hSucc n)
+
+
+-- Equality on labels
+
+instance HEq n n' b
+      => HEq (Label n) (Label n') b
+
+
+-- Show label
+
+instance Show n => ShowLabel (Label n)
+ where
+  showLabel (Label n) = show n
diff --git a/Data/HList/Label2.hs b/Data/HList/Label2.hs
new file mode 100644
--- /dev/null
+++ b/Data/HList/Label2.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, EmptyDataDecls #-}
+
+{-
+   The HList library
+
+   (C) 2004-2006, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
+
+   A model of labels as needed for extensible records. As before,
+   all the information about labels is recorded in their type, so
+   the labels of records may be purely phantom. In general,
+   Labels are exclusively type-level entities and have no run-time
+   representation.
+
+   Record labels are triplets of type-level naturals, namespace,
+   and description. The namespace part helps avoid confusions between
+   labels from different Haskell modules. The description is
+   an arbitrary nullary type constructor.
+   For the sake of printing, the namespace part and the description
+   are required to be the instance of Show. One must make sure that
+   the show functions does not examine the value, as descr is purely phantom.
+   Here's an example of the good Label description:
+        data MyLabelDescr; instance Show MyLabelDescr where show _ = "descr"
+   which obviously can be automated with Template Haskell.
+
+   This model requires all labels in a record to inhabit the same namespace.
+-}
+
+module Data.HList.Label2 where
+
+import Data.HList.FakePrelude
+import Data.HList.Record (ShowLabel(..))
+
+
+-- Labels are type-level naturals
+
+data HNat x => Label x ns desc  -- labels are exclusively type-level entities
+
+
+-- Construct the first label
+
+firstLabel :: ns -> desc -> Label HZero ns desc
+firstLabel = undefined
+
+
+-- Construct the next label
+nextLabel :: Label x ns desc -> desc' -> Label (HSucc x) ns desc'
+nextLabel = undefined
+
+
+-- Equality on labels (descriptions are ignored)
+
+instance HEq x x' b
+      => HEq (Label x ns desc1) (Label x' ns desc2) b
+
+
+-- Show label
+
+instance (HNat x, Show desc) => ShowLabel (Label x ns desc) where
+  showLabel = show . getd
+      where getd :: Label x ns desc -> desc
+            getd = undefined
+
+instance (HNat x, HNat2Integral x,Show ns) => Show (Label x ns desc) where
+  show l = unwords ["L",show ((hNat2Integral x)::Integer), show ns]
+      where geti :: Label x ns desc -> (x,ns) -- for the sake of Hugs
+            geti = undefined
+            (x,ns) = geti l
diff --git a/Data/HList/Label3.hs b/Data/HList/Label3.hs
new file mode 100644
--- /dev/null
+++ b/Data/HList/Label3.hs
@@ -0,0 +1,73 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, EmptyDataDecls #-}
+
+{-
+   The HList library
+
+   (C) 2004-2006, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
+
+   A model of labels as needed for extensible records. As before,
+   all the information about labels is recorded in their type, so
+   the labels of records may be purely phantom. In general,
+   Labels are exclusively type-level entities and have no run-time
+   representation.
+
+   Record labels are triplets of type-level naturals, namespace,
+   and description. The namespace part helps avoid confusions between
+   labels from different Haskell modules. The description is
+   an arbitrary nullary type constructor.
+   For the sake of printing, the description is required to be the
+   instance of Show. One must make sure that the show functions does
+   not examine the value, as descr is purely phantom. Here's an
+   example of the good Label description:
+        data MyLabelDescr; instance Show MyLabelDescr where show _ = "descr"
+   which obviously can be automated with Template Haskell.
+
+   This model even allows the labels in a record to belong to different
+   namespaces. To this end, the model employs the predicate for type
+   equality.
+-}
+
+module Data.HList.Label3 where
+
+import Data.HList.FakePrelude
+import Data.HList.Record (ShowLabel(..))
+
+
+-- Labels are type-level naturals
+data HNat x => Label x ns desc  -- labels are exclusively type-level entities
+
+
+-- Public constructors for labels
+
+-- Construct the first label
+firstLabel :: ns -> desc -> Label HZero ns desc
+firstLabel = undefined
+
+
+-- Construct the next label
+nextLabel :: Label x ns desc -> desc' -> Label (HSucc x) ns desc'
+nextLabel = undefined
+
+
+-- Equality on labels (descriptions are ignored)
+
+instance ( HEq x x' b
+         , TypeEq ns ns' b'
+         , HAnd b b' b''
+         )
+      =>   HEq (Label x ns desc) (Label x' ns' desc') b''
+
+
+-- Show label
+
+instance (HNat x, Show desc) => ShowLabel (Label x ns desc) where
+  showLabel = show . getd
+      where getd :: Label x ns desc -> desc -- for the sake of Hugs
+            getd = undefined
+
+instance (HNat x, Show desc) => Show (Label x ns desc)
+ where
+  show = show . getd
+      where getd :: Label x ns desc -> desc -- for the sake of Hugs
+            getd = undefined
+
diff --git a/Data/HList/Label5.hs b/Data/HList/Label5.hs
new file mode 100644
--- /dev/null
+++ b/Data/HList/Label5.hs
@@ -0,0 +1,40 @@
+{-# LANGUAGE FlexibleInstances, UndecidableInstances, MultiParamTypeClasses #-}
+
+{-
+   The HList library
+
+   (C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
+
+   Yet another model of labels.
+   This model allow us to use any type as label type.
+   As a result, we need some generic instances.
+   Also, type errors may be more confusing now.
+-}
+
+module Data.HList.Label5 where
+
+import Data.Typeable
+import Data.Char
+import Data.HList.FakePrelude
+import Data.HList.Record
+
+
+-- Equality on labels
+
+instance TypeEq x y b => HEq x y b
+
+
+-- Show label
+
+instance Typeable x => ShowLabel x
+ where
+  showLabel = (\(x:xs) -> toLower x:xs)
+            . reverse
+            . takeWhile (not . (==) '.')
+            . reverse
+            . show
+{-
+            . tyConString
+            . typeRepTyCon
+-}
+            . typeOf
diff --git a/Data/HList/Record.hs b/Data/HList/Record.hs
--- a/Data/HList/Record.hs
+++ b/Data/HList/Record.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
-  FlexibleContexts, UndecidableInstances #-}
-{-# OPTIONS -fglasgow-exts #-}
+  FlexibleContexts, UndecidableInstances, ScopedTypeVariables #-}
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
 
 {-
    The HList library
@@ -191,7 +191,6 @@
 {-----------------------------------------------------------------------------}
 
 -- Delete operation
-hDeleteAtLabel :: (H2ProjectByLabels (HCons e HNil) t t1 t2) => e -> Record t -> Record t2
 hDeleteAtLabel l (Record r) = Record r'
  where
   (_,r')  = h2projectByLabels (HCons l HNil) r
@@ -200,8 +199,6 @@
 {-----------------------------------------------------------------------------}
 
 -- Update operation
-hUpdateAtLabel ::( RecordLabels t ls, HFind e ls n, HUpdateAtHNat n (LVPair e v) t l') =>
-                e -> v -> Record t -> Record l'
 hUpdateAtLabel l v (Record r) = Record r'
  where
   n    = hFind l (recordLabels r)
@@ -215,8 +212,6 @@
 hProjectByLabels :: (HRLabelSet a, H2ProjectByLabels ls t a b) => ls -> Record t -> Record a
 hProjectByLabels ls (Record r) = mkRecord (fst $ h2projectByLabels ls r)
 
-hProjectByLabels2 :: (HRLabelSet t2, HRLabelSet t1, H2ProjectByLabels ls t t1 t2) =>
-                                                 ls -> Record t -> (Record t1, Record t2)
 hProjectByLabels2 ls (Record r) = (mkRecord rin, mkRecord rout)
    where (rin,rout) = h2projectByLabels ls r
 
@@ -256,9 +251,6 @@
 {-----------------------------------------------------------------------------}
 
 -- Rename the label of record
-hRenameLabel :: (H2ProjectByLabels (HCons e HNil) t t1 t2, HasField e t v,
-                HRLabelSet (HCons (LVPair l v) t2)) =>
-               e -> l -> Record t -> Record (HCons (LVPair l v) t2)
 hRenameLabel l l' r = r''
  where
   v   = hLookupByLabel l r
@@ -269,9 +261,6 @@
 {-----------------------------------------------------------------------------}
 
 -- A variation on update: type-preserving update.
-hTPupdateAtLabel :: (HUpdateAtHNat n (LVPair l a) t l', HFind l ls n, RecordLabels t ls,
-                    HasField l t a) =>
-                   l -> a -> Record t -> Record l'
 hTPupdateAtLabel l v r = hUpdateAtLabel l v r
  where
    te :: a -> a -> ()
diff --git a/Data/HList/RecordP.hs b/Data/HList/RecordP.hs
new file mode 100644
--- /dev/null
+++ b/Data/HList/RecordP.hs
@@ -0,0 +1,212 @@
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleContexts,
+  UndecidableInstances, FlexibleInstances #-}
+{-# OPTIONS -fglasgow-exts #-}
+
+{-
+   The HList library
+
+   (C) 2004-2006, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
+
+   Extensible records: labels are phantom, so at run-time, the record
+   is just a heterogenous list of field values.
+   This sort of record is generalizable to `tables' (which are, at
+   run-time, a list or a map containing the heterogenous lists
+   of field values).
+
+   The are different models of labels that go with this module;
+   see the files Label?.hs.
+-}
+
+module Data.HList.RecordP where
+
+import Data.HList.FakePrelude
+import Data.HList.HListPrelude
+import Data.HList.Record
+import Data.HList.HArray
+
+{-----------------------------------------------------------------------------}
+
+-- Record types as Phantom labels with values
+
+newtype RecordP ls vs = RecordP vs
+
+
+-- Build a record. I wonder if the 'ls' argument of mkRecordP can be
+-- removed. So far, we had no need for it...
+
+mkRecordP :: (HSameLength ls vs, HLabelSet ls) => ls -> vs -> RecordP ls vs
+mkRecordP _ vs = RecordP vs
+
+-- The contraint that two HLists have the same length
+class HSameLength l1 l2
+instance HSameLength HNil HNil
+instance HSameLength l1 l2 => HSameLength (HCons e1 l1) (HCons e2 l2)
+
+-- Build an empty record
+emptyRecordP :: RecordP HNil HNil
+emptyRecordP = mkRecordP HNil HNil
+
+-- Converting between RecordP and Record (label/value pairs)
+
+-- The following class declares a bijection between Record and recordP
+class HRLabelSet r => RecordR2P r ls vs | r -> ls vs, ls vs -> r where
+    record_r2p :: Record r -> RecordP ls vs
+    record_p2r :: RecordP ls vs -> Record r
+
+instance RecordR2P HNil HNil HNil where
+    record_r2p _ = emptyRecordP
+    record_p2r _ = emptyRecord
+
+instance (RecordR2P r ls vs, HRLabelSet (HCons (LVPair l v) r),
+          HLabelSet (HCons l ls), HSameLength ls vs)
+    => RecordR2P (HCons (LVPair l v) r) (HCons l ls) (HCons v vs) where
+    record_r2p (Record (HCons f r)) = hExtend f (record_r2p (Record r))
+    record_p2r (RecordP (HCons v r)) = hExtend (LVPair v) (record_p2r (RecordP r))
+
+labels_of_recordp :: RecordP ls vs -> ls
+labels_of_recordp = undefined
+
+
+{-----------------------------------------------------------------------------}
+
+-- A Show instance to appeal to normal records
+-- to save the coding time (rather than run-time), we just
+-- convert RecordP to regular Record, which we know how to show
+
+instance (RecordR2P r ls vs, ShowComponents r, HRLabelSet r) =>
+    Show (RecordP ls vs) where show rp = show $ record_p2r rp
+
+
+{-----------------------------------------------------------------------------}
+
+-- Extension for records
+
+instance (HLabelSet (HCons l ls), HSameLength ls vs)
+    => HExtend (LVPair l v) (RecordP ls vs) (RecordP (HCons l ls) (HCons v vs))
+ where
+  hExtend (LVPair v) (RecordP vs) = mkRecordP undefined (HCons v vs)
+
+
+{-----------------------------------------------------------------------------}
+
+-- Record concatenation
+
+instance ( HLabelSet ls''
+         , HAppend ls ls' ls''
+         , HAppend vs vs' vs''
+         , HSameLength ls'' vs''
+         )
+    => HAppend (RecordP ls vs) (RecordP ls' vs') (RecordP ls'' vs'')
+ where
+  hAppend (RecordP vs) (RecordP vs') = mkRecordP undefined (hAppend vs vs')
+
+{-----------------------------------------------------------------------------}
+
+-- Lookup operation
+
+-- Because hLookupByLabel is so frequent and important, we
+-- implement it separately. The algorithm is familiar assq,
+-- only the comparison operation is done at compile-time
+
+instance (HEq l l' b, HasFieldP' b l (RecordP (HCons l' ls) vs) v)
+    => HasField l (RecordP (HCons l' ls) vs) v where
+    hLookupByLabel = hLookupByLabelP' (undefined::b)
+
+class HasFieldP' b l r v | b l r -> v where
+    hLookupByLabelP' :: b -> l -> r -> v
+
+instance HasFieldP' HTrue l (RecordP (HCons l ls) (HCons v vs)) v where
+    hLookupByLabelP' _ _ (RecordP (HCons v _)) = v
+
+instance HasField l (RecordP ls vs) v
+    => HasFieldP' HFalse l (RecordP (HCons l' ls) (HCons v' vs)) v where
+    hLookupByLabelP' _ l (RecordP (HCons _ vs)) =
+        hLookupByLabel l ((RecordP vs)::RecordP ls vs)
+
+
+{-----------------------------------------------------------------------------}
+
+-- Delete operation
+hDeleteAtLabelP :: HProjectByLabelP l ls vs lso v vso =>
+                   l -> RecordP ls vs -> RecordP lso vso
+hDeleteAtLabelP l r = snd $ h2ProjectByLabelP l r
+
+
+{-----------------------------------------------------------------------------}
+
+-- Update operation
+hUpdateAtLabelP :: (HUpdateAtHNat n e1 t1 l', HFind e t n) => e -> e1 -> RecordP t t1 -> RecordP ls l'
+hUpdateAtLabelP l v rp@(RecordP vs) = RecordP (hUpdateAtHNat n v vs)
+ where
+  n       = hFind l (labels_of_recordp rp)
+
+{-----------------------------------------------------------------------------}
+-- Projection for records
+-- It is also an important operation: the basis of many
+-- deconstructors -- so we try to implement it efficiently.
+
+-- Project by a single label
+class HProjectByLabelP l ls vs lso v vso | l ls vs -> lso v vso where
+    h2ProjectByLabelP :: l -> RecordP ls vs -> (v,RecordP lso vso)
+
+instance (HEq l l' b, HProjectByLabelP' b l (HCons l' ls) vs lso v vso)
+    => HProjectByLabelP l (HCons l' ls) vs lso v vso where
+    h2ProjectByLabelP = h2ProjectByLabelP' (undefined::b)
+
+class HProjectByLabelP' b l ls vs lso v vso | b l ls vs -> lso v vso where
+    h2ProjectByLabelP' :: b -> l -> RecordP ls vs -> (v,RecordP lso vso)
+
+instance HProjectByLabelP' HTrue l (HCons l ls) (HCons v vs) ls v vs where
+    h2ProjectByLabelP' _ _ (RecordP (HCons v vs)) = (v,RecordP vs)
+
+instance (HProjectByLabelP l ls vs lso' v vso')
+    => HProjectByLabelP' HFalse l (HCons l' ls) (HCons v' vs)
+       (HCons l' lso') v (HCons v' vso') where
+    h2ProjectByLabelP' _ l (RecordP (HCons v' vs)) =
+        let (v,RecordP vso) = h2ProjectByLabelP l ((RecordP vs)::RecordP ls vs)
+        in (v, RecordP (HCons v' vso))
+
+
+-- Invariant: r = rin `disjoint-union` rout
+--            labels(rin) = ls
+-- classes H2ProjectByLabels and H2ProjectByLabels' are declared in
+-- Record.hs
+
+instance H2ProjectByLabels (HCons l ls)
+                           (RecordP HNil HNil) (RecordP HNil HNil)
+                           (RecordP HNil HNil)
+    where
+    h2projectByLabels _ _ = (emptyRecordP,emptyRecordP)
+
+instance (HMember l' ls b,
+          H2ProjectByLabels' b ls (RecordP (HCons l' ls') vs') rin rout)
+    => H2ProjectByLabels ls (RecordP (HCons l' ls') vs') rin rout where
+    h2projectByLabels = h2projectByLabels' (undefined::b)
+
+instance H2ProjectByLabels ls (RecordP ls' vs') (RecordP lin vin) rout =>
+    H2ProjectByLabels' HTrue ls (RecordP (HCons l' ls') (HCons v' vs'))
+                             (RecordP (HCons l' lin) (HCons v' vin)) rout where
+    h2projectByLabels' _ ls (RecordP (HCons v' vs')) =
+        (RecordP (HCons v' vin), rout)
+        where (RecordP vin,rout) =
+                  h2projectByLabels ls ((RecordP vs')::RecordP ls' vs')
+
+instance H2ProjectByLabels ls (RecordP ls' vs') rin (RecordP lo vo) =>
+    H2ProjectByLabels' HFalse ls (RecordP (HCons l' ls') (HCons v' vs'))
+                              rin (RecordP (HCons l' lo) (HCons v' vo)) where
+    h2projectByLabels' _ ls (RecordP (HCons v' vs')) =
+        (rin, RecordP (HCons v' vo))
+        where (rin,RecordP vo) =
+                  h2projectByLabels ls ((RecordP vs')::RecordP ls' vs')
+
+
+{-----------------------------------------------------------------------------}
+
+-- Subtyping for records
+
+-- Hmm, a bit too conservative. It works for all our examples,
+-- where the record extension is by simple extension. In the future,
+-- we should account for possible field permutation.
+
+instance H2ProjectByLabels ls' (RecordP ls vs) (RecordP ls' vs') rout
+    =>  SubType (RecordP ls vs) (RecordP ls' vs')
diff --git a/Data/HList/TIP.hs b/Data/HList/TIP.hs
--- a/Data/HList/TIP.hs
+++ b/Data/HList/TIP.hs
@@ -1,4 +1,7 @@
-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, FlexibleContexts, UndecidableInstances #-}
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances,
+    FlexibleContexts #-}
+
 module Data.HList.TIP where
 
 {-
@@ -73,7 +76,8 @@
 {-----------------------------------------------------------------------------}
 
 -- Type-indexed extension
-hExtend' :: (HTypeIndexed t, HOccursNot e t) => e -> TIP t -> TIP (HCons e t)
+-- signature is inferred
+-- hExtend' :: (HTypeIndexed t, HOccursNot e t) => e -> TIP t -> TIP (HCons e t)
 hExtend' e (TIP l) = mkTIP (HCons e l)
 
 {-
@@ -145,22 +149,16 @@
 {-----------------------------------------------------------------------------}
 
 -- Shielding type-indexed operations
+-- The absence of signatures is deliberate! They all must be inferred.
 
-onTIP :: HTypeIndexed a => (b -> a) -> TIP b -> TIP a
 onTIP f (TIP l) = mkTIP (f l)
 
-tipyDelete :: (HTypeIndexed l',HType2HNat e b n,HDeleteAtHNat n b l') => Proxy e -> TIP b -> TIP l'
 tipyDelete  p t  = onTIP (hDeleteAtProxy p) t
-tipyUpdate :: (HTypeIndexed l',HType2HNat e b n,HUpdateAtHNat n e b l') => e -> TIP b -> TIP l'
 tipyUpdate  e t  = onTIP (hUpdateAtType e) t
-tipyProject :: (HTypeIndexed l',HTypes2HNats ps b ns,HProjectByHNats ns b l') => ps -> TIP b -> TIP l'
 tipyProject ps t = onTIP (hProjectByProxies ps) t
 
 
 -- Split produces two TIPs
-tipySplit :: (HTypeIndexed t2,HTypeIndexed t1,HTypes2HNats ps t ns,HSplitByHNats' ns l' t1 t2,
-             HMap (HAddTag HTrue) t l') =>
-            ps -> TIP t -> (TIP t1, TIP t2)
 tipySplit ps (TIP l) = (mkTIP l',mkTIP l'')
  where
   (l',l'') = hSplitByProxies ps l
diff --git a/Data/HList/TypeCastGeneric2.hs b/Data/HList/TypeCastGeneric2.hs
new file mode 100644
--- /dev/null
+++ b/Data/HList/TypeCastGeneric2.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, FunctionalDependencies, UndecidableInstances #-}
+{-
+   The HList library
+
+   (C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
+
+   A generic implementation of a type-safe cast. The specific coding
+   here is only shown for completeness' sake and it is explained in the
+   TR version of the paper. The shown coding does not rely on separate
+   compilation (while TypeCastGeneric1.hs does), but on some other tricks.
+-}
+
+module Data.HList.TypeCastGeneric2 where
+
+-- We make everything self-contained to show that separate compilation
+-- is not needed.
+
+import Data.HList.FakePrelude () -- hiding (TypeCast,typeCast)
+
+
+{-----------------------------------------------------------------------------}
+
+-- The actual encoding
+
+class TypeCast   a b   | a -> b, b->a   where typeCast   :: a -> b
+class TypeCast'  t a b | t a -> b, t b -> a where typeCast'  :: t->a->b
+class TypeCast'' t a b | t a -> b, t b -> a where typeCast'' :: t->a->b
+instance TypeCast'  () a b => TypeCast a b where typeCast x = typeCast' () x
+instance TypeCast'' t a b => TypeCast' t a b where typeCast' = typeCast''
+instance TypeCast'' () a a where typeCast'' _ x  = x
+
+
+{-----------------------------------------------------------------------------}
diff --git a/Data/HList/TypeEqGeneric1.hs b/Data/HList/TypeEqGeneric1.hs
--- a/Data/HList/TypeEqGeneric1.hs
+++ b/Data/HList/TypeEqGeneric1.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
-  FlexibleContexts, UndecidableInstances #-}
+  FlexibleContexts, OverlappingInstances, UndecidableInstances #-}
 {-
    The HList library
 
diff --git a/Data/HList/TypeEqGeneric2.hs b/Data/HList/TypeEqGeneric2.hs
new file mode 100644
--- /dev/null
+++ b/Data/HList/TypeEqGeneric2.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleContexts, FlexibleInstances, UndecidableInstances #-}
+
+{-
+   The HList library
+
+   (C) 2004, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
+
+   A generic implementation of a type equality predicate. The given
+   implementation only works for GHC. The specific coding here is only
+   shown for completeness' sake. We actually favour the encoding from
+   TypeEqGeneric1.hs for its conciseness. The specific coding here
+   does not rely on separate compilation (while TypeEqGeneric1.hs
+   does), but on some other tricks.
+-}
+
+module Data.HList.TypeEqGeneric2 where
+
+-- We make everything self-contained to show that separate compilation
+-- is not needed. Also, we need a new class constraint for TypeEqBool,
+-- (unless we again employ separate compilation in some ways) so
+-- that instance selection of its generic instance within client code
+-- of TypeEqBool does not issue problems with the instance
+-- constraints.
+
+import Data.HList.FakePrelude hiding (TypeEq,typeEq,proxyEq,TypeCast,typeCast)
+import Data.HList.TypeCastGeneric2
+
+-- Re-enabled for testing
+
+typeEq :: TypeEq t t' b => t -> t' -> b
+typeEq = undefined
+
+
+{-----------------------------------------------------------------------------}
+
+-- The actual encoding
+
+class TypeEq' () x y b => TypeEq x y b | x y -> b
+class TypeEq' q x y b | q x y -> b
+class TypeEq'' q x y b | q x y -> b
+instance TypeEq' () x y b => TypeEq x y b
+-- This instance used to work <= GHC 6.2
+-- instance TypeEq' () x x HTrue
+-- There were some problems however with GHC CVS 6.3.
+-- So we favour the following, more stable (?) instance instead.
+instance TypeCast b HTrue => TypeEq' () x x b
+instance TypeEq'' q x y b => TypeEq' q x y b
+instance TypeEq'' () x y HFalse
+
+{-----------------------------------------------------------------------------}
diff --git a/HList.cabal b/HList.cabal
--- a/HList.cabal
+++ b/HList.cabal
@@ -1,26 +1,29 @@
 Name:                HList
-Version:             0.1
+Version:             0.1.1
 Category:            Data
 Synopsis:            Heterogeneous lists
 Description:         HList is a record system providing strongly typed heterogenous lists, records,
                      type-indexed products (TIP) and co-products; licensed under the MIT X License.
-License:             OtherLicense
+License:             MIT
 License-File:        LICENSE
 Author:              2004 Oleg Kiselyov (FNMOC, Monterey), Ralf Laemmel (CWI/VU, Amsterdam),
                      Keean Schupke (Imperial College, London)
 Maintainer:          oleg@pobox.com
 
+Data-files:          README, keyword-arguments.lhs
+Cabal-version:       >= 1.4
 Tested-With:         GHC==6.8.2
-Build-Depends:       base
+Build-Depends:       base >= 3 && < 5
 Build-Type:          Simple
-Exposed-modules:     Data.HList
-Other-modules:       Data.HList.Label4, Data.HList.CommonMain, Data.HList.Variant, Data.HList.GhcSyntax,
+Exposed-modules:     Data.HList, Data.HList.CommonMain, Data.HList.Variant, Data.HList.GhcSyntax,
                      Data.HList.GhcRecord, Data.HList.Record, Data.HList.HZip, Data.HList.TIC, Data.HList.TIP,
                      Data.HList.HTypeIndexed, Data.HList.HOccurs, Data.HList.HArray, Data.HList.GhcExperiments,
                      Data.HList.HListPrelude, Data.HList.TypeEqBoolGeneric, Data.HList.TypeEqGeneric1,
-                     Data.HList.TypeCastGeneric1, Data.HList.FakePrelude
+                     Data.HList.TypeCastGeneric1, Data.HList.TypeCastGeneric2, Data.HList.FakePrelude, 
+                     Data.HList.RecordP, Data.HList.TypeEqGeneric2,
+                     Data.HList.Label1, Data.HList.Label2, Data.HList.Label3, Data.HList.Label4, Data.HList.Label5
 
 extensions:          EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies,
-                     MultiParamTypeClasses, OverlappingInstances, PatternSignatures, RankNTypes,
+                     MultiParamTypeClasses, OverlappingInstances, ScopedTypeVariables, RankNTypes,
                      ScopedTypeVariables, TypeSynonymInstances, UndecidableInstances
-ghc-options:         -O2 -Wall
+ghc-options:         -Wall
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,22 @@
+(C) 2004--2005, Oleg Kiselyov, Ralf Laemmel, Keean Schupke
+
+The HList library and samples
+
+This distribution covers all essential issues discussed in the HList paper.
+Additional examples and HList operations are provided.
+The code from the database section of the HList paper is not included
+since doing so would have implied inclusion of substantial packages,
+namely the underlying infrastructure for database access library.
+
+You can get HList from Hackage or from Darcs:
+
+$ darcs get --partial http://darcs.haskell.org/HList/
+
+The code works --- within the limits exercised in the source files ---
+for both GHC (6.4) and Hugs (Nov 2003). See the Makefile for ways of
+running test cases.
+
+One may run "make test" to check the distribution.
+
+Last updated; February 08, 2006
+
diff --git a/keyword-arguments.lhs b/keyword-arguments.lhs
new file mode 100644
--- /dev/null
+++ b/keyword-arguments.lhs
@@ -0,0 +1,440 @@
+From oleg-at-okmij.org Fri Aug 13 14:58:35 2004
+To: haskell@haskell.org
+Subject: Keyword arguments
+From: oleg-at-pobox.com
+Message-ID: <20040813215834.F1FF3AB7E@Adric.metnet.navy.mil>
+Date: Fri, 13 Aug 2004 14:58:34 -0700 (PDT)
+Status: OR
+
+
+We show the Haskell implementation of keyword arguments, which goes
+well beyond records (e.g., in permitting the re-use of
+labels). Keyword arguments indeed look just like regular, positional
+arguments. However, keyword arguments may appear in any
+order. Furthermore, one may associate defaults with some keywords; the
+corresponding arguments may then be omitted. It is a type error to
+omit a required keyword argument. The latter property is in stark
+contrast with the conventional way of emulating keyword arguments via
+records. Also in marked contrast with records, keyword labels may be
+reused throughout the code with no restriction; the same label may be
+associated with arguments of different types in different
+functions. Labels of Haskell records may not be re-used.  Our solution
+is essentially equivalent to keyword arguments of DSSSL Scheme or
+labels of OCaml.
+
+Keyword argument functions are naturally polyvariadic: Haskell does
+support varargs! Keyword argument functions may be polymorphic. As
+usual, functions with keyword arguments may be partially applied. On
+the downside, sometimes one has to specify the type of the return
+value of the function (if the keyword argument function has no
+signature -- the latter is the norm, see below) -- provided that the
+compiler cannot figure the return type out on its own. This is usually
+only the case when we use keyword functions at the top level (GHCi
+prompt).
+
+Our solution requires no special extensions to Haskell and works with
+the existing Haskell compilers; it is tested on GHC 6.0.1. The
+overlapping instances extension is not necessary (albeit it is
+convenient).
+
+The gist of our implementation is the realization that the type of a
+function is a polymorphic collection of its argument types -- a
+collection that we can traverse. This message thus illustrates a
+limited form of the reflection on a function.
+
+
+Our implementation is a trivial extension of the strongly-typed
+polymorphic open records described in
+	http://homepages.cwi.nl/~ralf/HList/
+
+In fact, the implementation relies on the HList library.  To run the
+code (which this message is), one needs to download the HList library
+from the above site.
+
+The HList paper discusses the issue of labels in some detail. The
+paper gives three different representations. One of them needs no
+overlapping instances and is very portable. In this message, we chose
+a representation that relies on generic type equality and therefore
+needs overlapping instances as implemented in GHC. Again, this is
+merely an outcome of our non-deterministic choice. It should be
+emphasized that other choices are possible, which do not depend on 
+overlapping instances at all. Please see the HList paper for details.
+
+> {-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-}
+> {-# OPTIONS -fallow-overlapping-instances #-}
+> 
+> module KW where
+> 
+> import FakePrelude hiding (TypeEq,typeEq,proxyEq,TypeCast,typeCast)
+> import TypeEqGeneric2
+> import TypeCastGeneric2
+> import HListPrelude
+
+
+We will be using an example inspired by a graphics toolkit -- the area
+which really benefits from keyword arguments. We first define our
+labels and useful datatypes
+
+> data Color = Color
+> data Size  = Size
+> data Origin  = Origin
+> data RaisedBorder = RaisedBorder
+>
+> data CommonColor = Red | Green | Blue deriving Show
+> data RGBColor = RGBColor Int Int Int deriving Show
+
+and two functions:
+
+> make_square Size n Origin (x0,y0) Color (color::CommonColor) =
+>   unwords ["Square:", show n, "at", show (x0,y0), show color] ++ "\n"
+> 
+> make_rect Size (nx,ny) Origin (x0,y0) Color (color::RGBColor)
+> 	 RaisedBorder border =
+>   unwords ["Rectangle:", show (nx,ny), "at", show (x0,y0),
+> 	   show color, if border then "raised border" else ""] ++ "\n"
+
+
+We are not interested in really drawing squares and rectangles
+here. Therefore, make_square and make_rect return a String, which we
+can regard as a ``command'' to be passed to a low-level graphics
+library. The functions make_square and make_rect are genuine functions
+and can be used as such. They are not keyword argument functions, yet,
+but they set the stage. These functions can be considered an
+`interface' for the keyword argument functions. We should note that
+the functions are polymorphic: for example, `Size' can be any
+showable. We must also emphasize the re-use of the labels: The Color
+of a square is the value of the enumerated type CommonColor. OTH, the
+color of the rectangle is given as an RGB triple. The sizes of the
+square and of the rectangle are specified differently too, the same
+label notwithstanding.
+
+Once the user wrote the functions such as make_square and make_rect,
+he can _automatically_ convert them to their keyword
+alternatives. This transformation is done by a function 'kw'. The user
+should pass the positional-argument function (`labeled' as above),
+and an HList of default values for some of the labels. The latter may
+be HNil if all keyword arguments are required.
+
+The first example (no defaults)
+
+> tests1 :: String = 
+>     kw make_square HNil Size (1::Int) Origin (0::Int,10::Int) Color Red 
+	
+we can permute the arguments at wish
+
+> tests2 :: String = 
+>     kw make_square HNil Color Red Size (1::Int) Origin (0::Int,10::Int)  
+	
+we can also assign a name to a keyword function, or partially apply it:
+
+> tests3 = let f x = kw make_square HNil Color Red x
+> 	   in "here: " ++ f Origin (0::Int,10::Int) Size (1::Int) 
+	
+The dummy argument 'x' is merely to avoid the monomorphic
+restriction. The following is a more interesting example, with the
+defaults:
+
+> tests4 = let defaults = Origin .*. (0::Int,10::Int) .*.
+> 			  RaisedBorder .*. True .*.
+> 			  HNil
+> 	   in kw make_square defaults Size (1::Int) Color Red ++
+> 	      kw make_rect   defaults Color (RGBColor 0 10 255)
+> 	                              Size (1.0::Float, 2.0::Float)
+
+The argument RaisedBorder is not given, and so the default value is
+used. Of course, we can override the default:
+
+> tests5 = let defaults = Origin .*. (0::Int,10::Int) .*.
+> 			  RaisedBorder .*. True .*.
+> 			  HNil
+> 	       sq x = kw make_square defaults Color x
+> 	       re x = kw make_rect   defaults x
+> 	   in sq Red Size (1::Int) ++
+> 	      re Color (RGBColor 0 10 255)
+> 	         RaisedBorder False
+> 	         Size (1.0::Float, 2.0::Float)
+
+We have reshuffled a few arguments, just for fun. As you can see, the
+function `kw make_rect defaults' is polyvariadic indeed.  We chose to
+partially apply 'Color' to the function `kw make_square defaults' --
+so that the function `sq' is positional in its first argument, and
+keyword in the rest.
+
+If we omit a required argument, we get a type error:
+
+] testse1 = let f x = kw make_square HNil Color Red x
+] 	    in "here: " ++ f Origin (0::Int,10::Int) 
+
+  Couldn't match `ErrReqdArgNotFound Size' against `[Char]'
+      Expected type: ErrReqdArgNotFound Size
+      Inferred type: [Char] ...
+
+The error message seems reasonably clear. Likewise we get an error
+message if we pass to a keyword function an argument it does not expect:
+
+] testse2 = let f x = kw make_square HNil Color Red x
+] 	    in "here: " ++ f Origin (0::Int,10::Int) Size (1::Int) 
+]	                   RaisedBorder False
+
+  No instances for (Fail (ErrUnexpectedKW RaisedBorder),
+		    KWApply [Char] (HCons RaisedBorder (:*: Bool HNil)) [Char])
+      arising from use of `f' at ...
+    In the second argument of `(++)', namely
+	`f Origin (0 :: Int, 10 :: Int) Size (1 :: Int) RaisedBorder False'
+
+
+The function 'kw' receives the appropriately labeled function (such
+as make_square) and the HList with default values. The function 'kw'
+is polymorphic; the overloading is resolved based on the type of the
+user function *and* on the type of its continuation. The continuation
+indicates if a keyword argument is forthcoming, or not. In the latter
+case, 'kw' checks to see if the supplied defaults can provide the
+values of the still missing arguments. We see therefore that a
+function type is more than it may appear -- the type of a function is
+truly a heterogeneous, type level collection! The function 'kw'
+traverses that collection, thus performing a limited form of
+reflection on Haskell functions.
+ 
+
+Implementation Outline
+
+One of the key tools of the implementation is 'kwapply', which applies
+a function to a polymorphic collection of that function's arguments.
+The order of the arguments in the collection is irrelevant. The
+contraption kwapply can handle polymorphic functions with arbitrary
+number of labeled arguments.
+
+For example, if we define
+
+> f1 Size n = show n
+> f2 Size n Color m = unwords ["size:", show n, "color:", show m]
+> f3 Origin x Color m Size n = 
+>     unwords ["origin:", show x, "size:", show n, "color:",show m]
+
+then we can run
+
+> katest1  = kwapply f1 (Size .*. () .*. HNil)
+> katest11 = kwapply f1 (Size .*. "Large" .*. HNil)
+> 
+> katest2  = kwapply f2 (Size .*. (1::Int) .*. Color .*. Red .*. HNil)
+> katest21 = kwapply f2 (Color .*. Red .*. Size .*. (1::Int) .*.  HNil)
+> 
+> katest3  = kwapply f3 (Size .*. (1::Int) .*. Origin .*. (2.0::Float) .*. 
+> 		         Color .*. Red .*. HNil)
+
+Another key contraption is 
+
+> reflect_fk:: (ReflectFK fn kws) => fn -> Arg kws HNil
+> reflect_fk _ = Arg HNil
+
+that reflects on a user-supplied function. It converts the *type* of a
+user function to a collection of keywords required by that
+function. This and the previous contraptions may be used to define an
+`extended' version of some user function that takes more arguments --
+without the need to enumerate all arguments of the original
+function. We thus infringe on the area of object and module systems.
+
+The rest of the implementation is just to convert `kw fn defaults' 
+into the application of kwapply. 
+
+
+
+The rest of the implementation
+
+We should note that all implementation is written in the
+continuation-passing style (CPS) -- at the term level and especially
+at the _typeclass level_. One of the reasons is to avoid relying on
+overlapping instances: we compare types with a predicate `TypeEq x y
+hbool', obtain the type-level boolean, and dispatch to two
+non-overlapping instances of an auxiliary, continuation class. One
+instance handles HTrue, and the other the HFalse alternative. Please
+see the HList paper for more discussion of this technique.
+
+The other, equally important reason for the thorough CPS of the
+typeclasses is to control the order of evaluation of constraints and
+their functional dependencies. The sole reason is to produce
+informative error messages. The order of constraints is irrelevant
+when all the constraints are satisfied. However, if the user omitted a
+required keyword, many of the constraints below will fail. If a
+'wrong' constraint fails first, we get a totally off-the-wall error
+message that gives us no clue whatsoever about the problem. By tightly
+constraining the order via CPS, we are able to force the typechecker
+to give informative error messages.
+
+
+Preliminaries
+
+> -- A bit of syntax sugar for HLists
+> infixr 1 :*:
+> infixr 1 .*.
+> type e :*: l = HCons e l
+> (.*.) =  HCons
+
+
+Errors
+
+> data ErrReqdArgNotFound x
+> data ErrUnexpectedKW x
+> data Trace x
+
+All our keywords must be registered
+
+> class IsKeyFN   t flag | t-> flag
+> instance IsKeyFN (Color->a->b)  HTrue
+> instance IsKeyFN (Size->a->b)   HTrue
+> instance IsKeyFN (Origin->a->b) HTrue
+> instance IsKeyFN (RaisedBorder->a->b) HTrue
+> instance TypeCast HFalse flag => IsKeyFN t flag
+
+The implementation of KWApply
+
+> class KWApply f arg_values r | f arg_values -> r where
+>     kwapply:: f -> arg_values -> r
+> 
+> instance KWApply r HNil r where
+>     kwapply f _ = f
+> 
+> instance (TypeEq kw kw' flag,
+> 	  KWApply' flag (kw->a->f') (kw' :*: a' :*: tail) r)
+>     => KWApply (kw->a->f') (kw' :*: a' :*: tail) r where
+>     kwapply = kwapply' (undefined::flag)
+> 
+> class KWApply' flag f arg_values r  | flag f arg_values -> r  where
+>     kwapply':: flag -> f -> arg_values -> r
+> 
+> instance  (TypeCast v' v, KWApply f' tail r)
+>     => KWApply' HTrue (kw->v->f') (kw :*: v' :*: tail) r where
+>     kwapply' _ f (HCons kw (HCons v' tail)) = 
+>                    kwapply (f kw (typeCast v')) tail
+> 
+> -- Rotate the arg list ...
+> instance  (HAppend tail (kw :*: v :*: HNil) l',
+> 	   KWApply f l' r)
+>     => KWApply' HFalse f (kw :*: v :*: tail) r where
+>     kwapply' _ f (HCons kw (HCons v tail)) = 
+> 	kwapply f (hAppend tail (kw .*. v .*. HNil))
+
+The datatype Arg below is to maintain the state of keyword
+accumulation: which keywords we need, and which keyword and values we
+have already got.
+arg_types is the phantom HList of keywords that are yet to be satisfied.
+arg_values is the HList (kw .*. kw_value .*. etc)
+of already found keywords and their values.
+
+> newtype Arg arg_types arg_values = Arg arg_values deriving Show
+
+Reflection on a function:
+Given a function, return the type list of its keywords
+
+> class ReflectFK f kws | f -> kws
+> instance (IsKeyFN f flag, ReflectFK' flag f kws) => ReflectFK f kws
+> class ReflectFK' flag f kws | flag f -> kws
+> instance ReflectFK rest kws => ReflectFK' HTrue (kw->a->rest) (HCons kw kws)
+> instance ReflectFK' HFalse f HNil
+
+-- :t reflect_fk (undefined::Size->Int->Color->CommonColor->String)
+-- :t reflect_fk (undefined::Size->Int->()->Int)
+
+The main class: collect and apply the keyword arguments
+
+> class KW f arg_desc arg_def r where
+>     kwdo :: f -> arg_desc -> arg_def -> r
+> 
+> instance (IsKeyFN r rflag, -- Fail (Trace (arg_desc,r)),
+> 	    KW' rflag f arg_desc arg_def r)
+>     => KW f arg_desc arg_def r where
+>     kwdo = kw' (undefined::rflag)
+> 
+> class KW' rflag f arg_desc arg_def r where
+>     kw' :: rflag -> f -> arg_desc -> arg_def -> r
+
+If the continuation r does not promise any more keyword
+arguments, apply the defaults
+
+> instance KWMerge arg_needed arg_values arg_def f r
+>     => KW' HFalse f (Arg arg_needed arg_values) arg_def r where
+>     kw' _ f args_given arg_def = kwmerge args_given arg_def f
+
+Otherwise, collect the supplied keyword and its value, and recurse for
+more:
+
+> instance KWAcc arg_desc kw a f arg_def r
+>     => KW' HTrue f arg_desc arg_def (kw->a->r) where
+>     kw' _ f arg_desc arg_def kw a = kwaccum arg_desc kw a f arg_def
+
+
+Add the needed arguments from arg_def to arg_values and continue
+with kwapply.
+That is, we try to satisfy the missing arguments from the defaults.
+It will be a type error if some required arguments are missing
+
+> class KWMerge arg_needed arg_values arg_def f r |
+>               arg_needed arg_values arg_def f -> r  where
+>     kwmerge:: Arg arg_needed arg_values -> arg_def -> f -> r
+> 
+> instance KWApply f arg_values r 
+>     => KWMerge HNil arg_values arg_def f r where
+>     kwmerge (Arg arg_values) _ f = kwapply f arg_values
+> 
+> instance KWMerge' kw arg_def atail arg_values arg_def f r
+>     => KWMerge (HCons kw atail) arg_values arg_def f r where
+>     kwmerge (Arg arg_values) arg_def = 
+> 	kwmerge' (undefined::kw) arg_def
+> 	         ((Arg arg_values)::Arg atail arg_values) arg_def
+> 
+> class KWMerge' kw list atail arg_values arg_def f r | 
+>                kw list atail arg_values arg_def f -> r where
+>     kwmerge':: kw -> list -> (Arg atail arg_values) -> arg_def -> f -> r
+> 
+> instance Fail (ErrReqdArgNotFound kw)
+>     => KWMerge' kw HNil atail arg_values arg_def f
+>                 (ErrReqdArgNotFound kw) where
+>     kwmerge' = undefined
+> instance (TypeEq kw kw' flag,
+> 	  KWMerge'' flag kw (kw' :*: etc) atail arg_values arg_def f r)
+>     => KWMerge' kw (kw' :*: etc) atail arg_values arg_def f r where
+>     kwmerge' = kwmerge'' (undefined::flag)
+> 
+> class KWMerge'' flag kw list atail arg_values arg_def f r |
+>                 flag kw list atail arg_values arg_def f -> r where
+>     kwmerge'':: flag -> kw -> list -> (Arg atail arg_values) -> arg_def
+> 		-> f -> r
+> instance KWMerge atail (kw :*: v :*: arg_values) arg_def f r
+>     => KWMerge'' HTrue kw (kw :*: v :*: tail)
+>                  atail arg_values arg_def f r where
+>     kwmerge'' _ _ (HCons kw (HCons v _)) (Arg arg_values) =
+> 	kwmerge ((Arg (kw .*. v .*. arg_values))::
+> 		 (Arg atail (kw :*: v :*: arg_values)))
+> instance KWMerge' kw tail atail arg_values arg_def f r
+>     => KWMerge'' HFalse kw (kw' :*: v' :*: tail)
+>                  atail arg_values arg_def f r where
+>     kwmerge'' _ kw (HCons _ (HCons _ tail)) = kwmerge' kw tail
+
+Add the real argument to the Arg structure, and continue
+
+> class KWAcc arg_desc kw a f arg_def r where
+>     kwaccum:: arg_desc -> kw -> a -> f -> arg_def -> r
+> 
+> instance (HDelete kw arg_types arg_types',
+> 	  KW f (Arg arg_types' (kw :*: a :*: arg_values)) arg_def r)
+>     => KWAcc (Arg arg_types arg_values) kw a f arg_def r  where
+>     kwaccum (Arg arg_values) kw a f = 
+> 	kwdo f (Arg (kw .*. a .*. arg_values)::
+> 		Arg arg_types' (kw :*: a :*: arg_values))
+
+Delete e from l to yield l' The element e must occur in l
+
+> class HDelete e l l' | e l -> l'
+> instance Fail (ErrUnexpectedKW e) => HDelete e HNil HNil
+> instance (TypeEq e e' flag, HDelete' flag e (HCons e' tail) l')
+>     => HDelete e (HCons e' tail) l'
+> class HDelete' flag e l l' | flag e l -> l'
+> instance HDelete' HTrue e (HCons e tail) tail
+> instance HDelete e tail tail'
+>     => HDelete' HFalse e (HCons e' tail) (HCons e' tail')
+
+Finally,
+
+> kw f = kwdo f (reflect_fk f)
+
+
