module Data.HList.Record
(
module Data.Tagged,
(.=.), (.-.),
Record(..),
mkRecord,
emptyRecord,
RecordLabels,
recordLabels,
LabelsOf,
hLabels,
RecordValues(..),
recordValues,
ShowComponents(..),
ShowLabel(..),
hDeleteAtLabel,
hLens,
HasField(..),
HasField'(..),
(.!.),
(.@.),
hUpdateAtLabel,
(.<.),
hTPupdateAtLabel,
hRenameLabel,
hProjectByLabels,
hProjectByLabels2,
HLeftUnion(hLeftUnion),
HLeftUnionBool(hLeftUnionBool),
(.<++.),
UnionSymRec(unionSR),
hRearrange,
(.*.),
DuplicatedLabel,
ExtraField(..),
FieldNotFound(..),
H2ProjectByLabels(h2projectByLabels),
H2ProjectByLabels'(h2projectByLabels'),
HLabelSet,
HLabelSet',
HRLabelSet,
HRLabelSet',
HRearrange(hRearrange2),
HRearrange'(hRearrange2'),
UnionSymRec'(..),
labelLVPair,
newLVPair,
) where
import Data.HList.FakePrelude
import Data.HList.HListPrelude
import Data.HList.HList
import Data.HList.HArray
import Data.Tagged
import Data.HList.Label6 ()
import Data.HList.TypeEqO ()
labelLVPair :: Tagged l v -> Label l
labelLVPair _ = Label
newLVPair :: Label l -> v -> Tagged l v
newLVPair _ = Tagged
infixr 4 .=.
(.=.) :: Label l -> v -> Tagged l v
l .=. v = newLVPair l v
newtype Record (r :: [*]) = Record (HList r)
mkRecord :: HRLabelSet r => HList r -> Record r
mkRecord = Record
emptyRecord :: Record '[]
emptyRecord = mkRecord HNil
data DuplicatedLabel l
class HRLabelSet (ps :: [*])
instance HRLabelSet '[]
instance HRLabelSet '[x]
instance ( HEq l1 l2 leq
, HRLabelSet' l1 l2 leq r
) => HRLabelSet (Tagged l1 v1 ': Tagged l2 v2 ': r)
class HRLabelSet' l1 l2 (leq::Bool) (r :: [*])
instance ( HRLabelSet (Tagged l2 () ': r)
, HRLabelSet (Tagged l1 () ': r)
) => HRLabelSet' l1 l2 False r
instance ( Fail (DuplicatedLabel l1) ) => HRLabelSet' l1 l2 True r
class HLabelSet ls
instance HLabelSet '[]
instance HLabelSet '[x]
instance ( HEq l1 l2 leq
, HLabelSet' l1 l2 leq r
) => HLabelSet (l1 ': l2 ': r)
class HLabelSet' l1 l2 (leq::Bool) r
instance ( HLabelSet (l2 ': r)
, HLabelSet (l1 ': r)
) => HLabelSet' l1 l2 False r
instance ( Fail (DuplicatedLabel l1) ) => HLabelSet' l1 l2 True r
type family RecordLabels (r :: [*]) :: [k]
type instance RecordLabels '[] = '[]
type instance RecordLabels (Tagged l v ': r) = l ': RecordLabels r
recordLabels :: Record r -> Proxy (RecordLabels r)
recordLabels _ = Proxy
class RecordValues (r :: [*]) where
type RecordValuesR r :: [*]
recordValues' :: HList r -> HList (RecordValuesR r)
instance RecordValues '[] where
type RecordValuesR '[] = '[]
recordValues' _ = HNil
instance RecordValues r=> RecordValues (Tagged l v ': r) where
type RecordValuesR (Tagged l v ': r) = v ': RecordValuesR r
recordValues' (HCons (Tagged v) r) = HCons v (recordValues' r)
recordValues :: RecordValues r => Record r -> HList (RecordValuesR r)
recordValues (Record r) = recordValues' r
type family LabelsOf (ls :: [*]) :: [*]
type instance LabelsOf '[] = '[]
type instance LabelsOf (Label l ': r) = l ': LabelsOf r
hLabels :: HList l -> Proxy (LabelsOf l)
hLabels _ = Proxy
instance ShowComponents r => Show (Record r) where
show (Record r) = "Record{"
++ showComponents "" r
++ "}"
class ShowComponents l where
showComponents :: String -> HList l -> String
instance ShowComponents '[] where
showComponents _ _ = ""
instance ( ShowLabel l
, Show v
, ShowComponents r
)
=> ShowComponents (Tagged l v ': r) where
showComponents comma (HCons f@(Tagged v) r)
= comma
++ showLabel ((labelLVPair f) :: Label l)
++ "="
++ show v
++ showComponents "," r
instance HRLabelSet (Tagged l v ': r)
=> HExtend (Tagged (l :: k) v) (Record r) where
type HExtendR (Tagged l v) (Record r) = Record (Tagged l v ': r)
f .*. (Record r) = mkRecord (HCons f r)
instance (HRLabelSet (HAppendList r1 r2), HAppend (HList r1) (HList r2))
=> HAppend (Record r1) (Record r2) where
hAppend (Record r) (Record r') = mkRecord (hAppend r r')
type instance HAppendR (Record r1) (Record r2) = Record (HAppendList r1 r2)
class HasField (l::k) r v | l r -> v where
hLookupByLabel:: Label l -> r -> v
instance (HEq l l1 b, HasField' b l (Tagged l1 v1 ': r) v)
=> HasField l (Record (Tagged l1 v1 ': r)) v where
hLookupByLabel l (Record r) =
hLookupByLabel' (Proxy::Proxy b) l r
class HasField' (b::Bool) (l :: k) (r::[*]) v | b l r -> v where
hLookupByLabel':: Proxy b -> Label l -> HList r -> v
instance HasField' True l (Tagged l v ': r) v where
hLookupByLabel' _ _ (HCons (Tagged v) _) = v
instance HasField l (Record r) v => HasField' False l (fld ': r) v where
hLookupByLabel' _ l (HCons _ r) = hLookupByLabel l (Record r)
infixr 9 .!.
(.!.) :: (HasField l r v) => r -> Label l -> v
r .!. l = hLookupByLabel l r
hDeleteAtLabel :: forall l t t1 t2.
(H2ProjectByLabels '[l] t t1 t2) =>
Label l -> Record t -> Record t2
hDeleteAtLabel _ (Record r) =
Record $ snd $ h2projectByLabels (Proxy::Proxy '[l]) r
infixl 2 .-.
(.-.) :: (H2ProjectByLabels '[l] r _r' r') =>
Record r -> Label l -> Record r'
r .-. l = hDeleteAtLabel l r
hUpdateAtLabel :: forall (r :: [*]) (l :: k) (n::HNat) (v :: *).
(HFind l (RecordLabels r) n, HUpdateAtHNat n (Tagged l v) r) =>
Label l -> v -> Record r -> Record (HUpdateAtHNatR n (Tagged l v) r)
hUpdateAtLabel l v (Record r) =
Record (hUpdateAtHNat (Proxy::Proxy n) (newLVPair l v) r)
infixr 2 .@.
f@(Tagged v) .@. r = hUpdateAtLabel (labelLVPair f) v r
hProjectByLabels :: (HRLabelSet a, H2ProjectByLabels ls t a b) =>
Proxy ls -> Record t -> Record a
hProjectByLabels ls (Record r) = mkRecord (fst $ h2projectByLabels ls r)
hProjectByLabels2 ::
(H2ProjectByLabels ls t t1 t2, HRLabelSet t1, HRLabelSet t2) =>
Proxy ls -> Record t -> (Record t1, Record t2)
hProjectByLabels2 ls (Record r) = (mkRecord rin, mkRecord rout)
where (rin,rout) = h2projectByLabels ls r
class H2ProjectByLabels (ls::[k]) r rin rout | ls r -> rin rout where
h2projectByLabels :: Proxy ls -> HList r -> (HList rin,HList rout)
instance H2ProjectByLabels '[] r '[] r where
h2projectByLabels _ r = (HNil,r)
instance H2ProjectByLabels (l ': ls) '[] '[] '[] where
h2projectByLabels _ _ = (HNil,HNil)
instance (HMemberM l1 ((l::k) ': ls) (b :: Maybe [k]),
H2ProjectByLabels' b (l ': ls) (Tagged l1 v1 ': r1) rin rout)
=> H2ProjectByLabels (l ': ls) (Tagged l1 v1 ': r1) rin rout where
h2projectByLabels = h2projectByLabels' (Proxy::Proxy b)
class H2ProjectByLabels' (b::Maybe [k]) (ls::[k]) r rin rout
| b ls r -> rin rout where
h2projectByLabels' :: Proxy b -> Proxy ls ->
HList r -> (HList rin,HList rout)
instance H2ProjectByLabels ls1 r rin rout =>
H2ProjectByLabels' ('Just ls1) ls (f ': r) (f ': rin) rout where
h2projectByLabels' _ _ (HCons x r) = (HCons x rin, rout)
where (rin,rout) = h2projectByLabels (Proxy::Proxy ls1) r
instance H2ProjectByLabels ls r rin rout =>
H2ProjectByLabels' 'Nothing ls (f ': r) rin (f ': rout) where
h2projectByLabels' _ ls (HCons x r) = (rin, HCons x rout)
where (rin,rout) = h2projectByLabels ls r
hRenameLabel l l' r = r''
where
v = hLookupByLabel l r
r' = hDeleteAtLabel l r
r'' = newLVPair l' v .*. r'
hTPupdateAtLabel l v r = hUpdateAtLabel l v r
where
_te :: a -> a -> ()
_te _ _ = ()
_ = _te v (hLookupByLabel l r)
infixr 2 .<.
f@(Tagged v) .<. r = hTPupdateAtLabel (labelLVPair f) v r
instance H2ProjectByLabels (RecordLabels r2) r1 r2 rout
=> SubType (Record r1) (Record r2)
class HLeftUnion r r' r'' | r r' -> r''
where hLeftUnion :: Record r -> Record r' -> Record r''
instance HLeftUnion r '[] r
where hLeftUnion r _ = r
instance ( RecordLabels r ~ ls
, HMember l ls b
, HLeftUnionBool b r (Tagged l v) r'''
, HLeftUnion r''' r' r''
)
=> HLeftUnion r (Tagged l v ': r') r''
where
hLeftUnion r (Record (HCons f r')) = r''
where
r''' = hLeftUnionBool (Proxy :: Proxy b) r f
r'' = hLeftUnion (r''' :: Record r''') (Record r' :: Record r')
class HLeftUnionBool (b :: Bool) r f r' | b r f -> r'
where hLeftUnionBool :: Proxy b -> Record r -> f -> Record r'
instance HLeftUnionBool True r f r
where hLeftUnionBool _ r _ = r
instance HLeftUnionBool False r f (f ': r)
where hLeftUnionBool _ (Record r) f = Record (HCons f r)
infixl 1 .<++.
(.<++.) :: (HLeftUnion r r' r'') => Record r -> Record r' -> Record r''
r .<++. r' = hLeftUnion r r'
class UnionSymRec r1 r2 ru | r1 r2 -> ru where
unionSR :: Record r1 -> Record r2 -> (Record ru, Record ru)
instance UnionSymRec r1 '[] r1 where
unionSR r1 _ = (r1, r1)
instance ( RecordLabels r1 ~ ls
, HMember l ls b
, UnionSymRec' b r1 (Tagged l v) r2' ru
)
=> UnionSymRec r1 (Tagged l v ': r2') ru
where
unionSR r1 (Record (HCons f r2')) =
unionSR' (Proxy::Proxy b) r1 f (Record r2')
class UnionSymRec' (b :: Bool) r1 f2 r2' ru | b r1 f2 r2' -> ru where
unionSR' :: Proxy b -> Record r1 -> f2 -> Record r2' -> (Record ru, Record ru)
instance (UnionSymRec r1 r2' ru,
HasField l2 (Record ru) v2,
HUpdateAtHNat n (Tagged l2 v2) ru,
ru ~ HUpdateAtHNatR n (Tagged l2 v2) ru,
RecordLabels ru ~ ls,
f2 ~ Tagged l2 v2,
HFind l2 ls n)
=> UnionSymRec' True r1 f2 r2' ru where
unionSR' _ r1 (Tagged v2) r2' =
case unionSR r1 r2'
of (ul,ur) -> (ul, hTPupdateAtLabel (Label :: Label l2) v2 ur)
instance (UnionSymRec r1 r2' ru,
HExtend f2 (Record ru),
HExtendR f2 (Record ru) ~ Record f2ru)
=> UnionSymRec' False r1 f2 r2' f2ru where
unionSR' _ r1 f2 r2' = (ul', ur')
where (ul,ur) = unionSR r1 r2'
ul' = f2 .*. ul
ur' = f2 .*. ur
hRearrange :: (HLabelSet ls, HRearrange ls r (HList r')) => Proxy ls -> Record r -> Record r'
hRearrange ls (Record r) = Record (hRearrange2 ls r)
class HRearrange ls r r' where
hRearrange2 :: Proxy ls -> HList r -> r'
instance (HList '[] ~ r) => HRearrange '[] '[] r where
hRearrange2 _ _ = HNil
instance (H2ProjectByLabels '[l] r rin rout,
HRearrange' l ls rin rout (HList r'),
r'' ~ HList r') =>
HRearrange (l ': ls) r r'' where
hRearrange2 _ r = hRearrange2' (Proxy :: Proxy l) (Proxy :: Proxy ls) rin rout
where (rin, rout) = h2projectByLabels (Proxy :: Proxy '[l]) r
class HRearrange' l ls rin rout r' where
hRearrange2' :: Proxy l -> Proxy ls -> HList rin -> HList rout -> r'
instance (HRearrange ls rout (HList r'),
r'' ~ HList (Tagged l v ': r')) =>
HRearrange' l ls '[Tagged l v] rout r'' where
hRearrange2' _ ls (HCons lv@(Tagged v) _HNil) rout
= HCons (Tagged v `asTypeOf` lv) (hRearrange2 ls rout)
data ExtraField l = ExtraField
data FieldNotFound l = FieldNotFound
instance Fail (FieldNotFound l) =>
HRearrange' l ls '[] rout (FieldNotFound l) where
hRearrange2' _ _ _ _ = FieldNotFound
instance Fail (ExtraField l) =>
HRearrange '[] (Tagged l v ': a) (ExtraField l) where
hRearrange2 _ _ = ExtraField
hLens lab f rec = fmap (\v -> hUpdateAtLabel lab v rec) (f (rec .!. lab))