{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Row.Records
(
Label(..)
, KnownSymbol, AllUniqueLabels, WellBehaved
, Rec, Row, Empty, type (≈)
, empty
, type (.==), (.==), pattern (:==), unSingleton
, default', defaultA
, fromLabels, fromLabelsA, fromLabelsMapA
, extend, Extend, Lacks, type (.\)
, type (.-), (.-)
, lazyRemove
, restrict, split
, update, focus, multifocus, Modify, rename, Rename
, HasType, type (.!), (.!)
, type (.+), (.+), Disjoint, pattern (:+)
, type (.//), (.//)
, curryRec
, (.$)
, fromNative, toNative, toNativeGeneral
, FromNative, ToNative, ToNativeGeneral
, NativeRow
, toDynamicMap, fromDynamicMap
, Map, map, map', mapF
, transform, transform'
, zipTransform, zipTransform'
, BiForall, Forall, erase, eraseWithLabels, eraseZip, eraseToHashMap
, Zip, zip
, traverse, traverseMap
, sequence, sequence'
, distribute
, compose, uncompose
, compose', uncompose'
, labels, labels'
, coerceRec
)
where
import Prelude hiding (map, sequence, traverse, zip)
import Control.DeepSeq (NFData(..), deepseq)
import Data.Bifunctor (Bifunctor(..))
import Data.Coerce
import Data.Dynamic
import Data.Functor.Compose
import Data.Functor.Const
import Data.Functor.Identity
import Data.Functor.Product
import Data.Generics.Product.Fields (HasField(..), HasField'(..))
import Data.Hashable
import Data.HashMap.Lazy (HashMap)
import qualified Data.HashMap.Lazy as M
import qualified Data.List as L
import Data.Monoid (Endo(..), appEndo)
import Data.Proxy
import Data.String (IsString)
import Data.Text (Text)
import qualified GHC.Generics as G
import GHC.TypeLits
import Unsafe.Coerce
import Data.Row.Dictionaries
import Data.Row.Internal
newtype Rec (r :: Row *) where
OR :: HashMap Text HideType -> Rec r
instance Forall r Show => Show (Rec r) where
showsPrec p r =
case eraseWithLabels @Show (showsPrec 7) r of
[] ->
showString "empty"
xs ->
showParen
(p > 6)
(appEndo $ foldMap Endo (L.intersperse (showString " .+ ") (L.map binds xs)))
where
binds (label, value) =
showChar '#' .
showString label .
showString " .== " .
value
instance Forall r Eq => Eq (Rec r) where
r == r' = and $ eraseZip @Eq (==) r r'
instance (Forall r Eq, Forall r Ord) => Ord (Rec r) where
compare m m' = cmp $ eraseZip @Ord compare m m'
where cmp l | [] <- l' = EQ
| a : _ <- l' = a
where l' = dropWhile (== EQ) l
instance (Forall r Bounded, AllUniqueLabels r) => Bounded (Rec r) where
minBound = default' @Bounded minBound
maxBound = default' @Bounded maxBound
instance Forall r NFData => NFData (Rec r) where
rnf r = getConst $ metamorph @_ @r @NFData @(,) @Rec @(Const ()) @Identity Proxy empty doUncons doCons r
where empty = const $ Const ()
doUncons l = second Identity . lazyUncons l
doCons _ (r, x) = deepseq x $ deepseq r $ Const ()
empty :: Rec Empty
empty = OR M.empty
infix 7 .==
(.==) :: KnownSymbol l => Label l -> a -> Rec (l .== a)
l .== a = extend l a empty
{-# COMPLETE (:==) #-}
infix 7 :==
pattern (:==) :: forall l a. KnownSymbol l => Label l -> a -> Rec (l .== a)
pattern l :== a <- (unSingleton @l @a -> (l, a)) where
(:==) l a = l .== a
unSingleton :: forall l a. KnownSymbol l => Rec (l .== a) -> (Label l, a)
unSingleton r = (l, r .! l) where l = Label @l
extend :: forall a l r. KnownSymbol l => Label l -> a -> Rec r -> Rec (Extend l a r)
extend (toKey -> l) a (OR m) = OR $ M.insert l (HideType a) m
update :: (KnownSymbol l, r .! l ≈ a) => Label l -> a -> Rec r -> Rec r
update (toKey -> l) a (OR m) = OR $ M.adjust f l m where f = const (HideType a)
focus ::
( KnownSymbol l
, r' .! l ≈ b
, r .! l ≈ a
, r' ~ Modify l b r
, r ~ Modify l a r'
, Functor f)
=> Label l -> (a -> f b) -> Rec r -> f (Rec r')
focus (toKey -> l) f (OR m) = case m M.! l of
HideType x -> OR . flip (M.insert l) m . HideType <$> f (unsafeCoerce x)
multifocus :: forall u v r f.
( Functor f
, Disjoint u r
, Disjoint v r)
=> (Rec u -> f (Rec v)) -> Rec (u .+ r) -> f (Rec (v .+ r))
multifocus f (u :+ r) = (.+ r) <$> f u
rename :: (KnownSymbol l, KnownSymbol l') => Label l -> Label l' -> Rec r -> Rec (Rename l l' r)
rename (toKey -> l) (toKey -> l') (OR m) = OR $ M.insert l' (m M.! l) $ M.delete l m
(.!) :: KnownSymbol l => Rec r -> Label l -> r .! l
OR m .! (toKey -> a) = case m M.! a of
HideType x -> unsafeCoerce x
infixl 6 .-
(.-) :: KnownSymbol l => Rec r -> Label l -> Rec (r .- l)
OR m .- (toKey -> a) = OR $ M.delete a m
infixl 6 .+
(.+) :: forall l r. FreeForall l => Rec l -> Rec r -> Rec (l .+ r)
OR l .+ OR r = OR $ M.unionWithKey choose l r
where
choose k lv rv = if k `elem` labels' @l @Text then lv else rv
(.//) :: Rec r -> Rec r' -> Rec (r .// r')
OR l .// OR r = OR $ M.union l r
{-# COMPLETE (:+) #-}
infixl 6 :+
pattern (:+) :: forall l r. Disjoint l r => Rec l -> Rec r -> Rec (l .+ r)
pattern l :+ r <- (split @l -> (l, r)) where
(:+) l r = l .+ r
split :: forall s r. (Subset s r, FreeForall s)
=> Rec r -> (Rec s, Rec (r .\\ s))
split (OR m) = (OR $ M.intersection m labelMap, OR $ M.difference m labelMap)
where
labelMap = M.fromList $ L.zip (labels' @s) (repeat ())
restrict :: forall r r'. (FreeForall r, Subset r r') => Rec r' -> Rec r
restrict = fst . split
lazyRemove :: KnownSymbol l => Label l -> Rec r -> Rec (r .- l)
lazyRemove _ (OR m) = OR m
lazyUncons :: KnownSymbol l => Label l -> Rec r -> (Rec (r .- l), r .! l)
lazyUncons l r = (lazyRemove l r, r .! l)
curryRec :: forall l t r x. KnownSymbol l => Label l -> (Rec (l .== t .+ r) -> x) -> t -> Rec r -> x
curryRec l f t r = f $ (l .== t) .+ r
infixl 2 .$
(.$) :: (KnownSymbol l, r' .! l ≈ t) => (Rec (l .== t .+ r) -> x) -> (Label l, Rec r') -> Rec r -> x
(.$) f (l, r') r = curryRec l f (r' .! l) r
newtype Pair' a = Pair' { unPair' :: (a,a) }
erase :: forall c ρ b. Forall ρ c => (forall a. c a => a -> b) -> Rec ρ -> [b]
erase f = fmap (snd @String) . eraseWithLabels @c f
eraseWithLabels :: forall c ρ s b. (Forall ρ c, IsString s) => (forall a. c a => a -> b) -> Rec ρ -> [(s,b)]
eraseWithLabels f = getConst . metamorph @_ @ρ @c @(,) @Rec @(Const [(s,b)]) @Identity Proxy doNil doUncons doCons
where doNil _ = Const []
doUncons l = second Identity . lazyUncons l
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ)
=> Label ℓ -> (Const [(s,b)] ρ, Identity τ) -> Const [(s,b)] (Extend ℓ τ ρ)
doCons l (Const c, Identity x) = Const $ (show' l, f x) : c
eraseZip :: forall c ρ b. Forall ρ c => (forall a. c a => a -> a -> b) -> Rec ρ -> Rec ρ -> [b]
eraseZip f x y = getConst $ metamorph @_ @ρ @c @(,) @(Product Rec Rec) @(Const [b]) @Pair' Proxy (const $ Const []) doUncons doCons (Pair x y)
where doUncons l (Pair r1 r2) = (Pair r1' r2', Pair' (a, b))
where (r1', a) = lazyUncons l r1
(r2', b) = lazyUncons l r2
doCons :: forall ℓ τ ρ. c τ
=> Label ℓ -> (Const [b] ρ, Pair' τ) -> Const [b] (Extend ℓ τ ρ)
doCons _ (Const c, unPair' -> x) = Const $ uncurry f x : c
eraseToHashMap :: forall c r s b. (IsString s, Eq s, Hashable s, Forall r c) =>
(forall a . c a => a -> b) -> Rec r -> HashMap s b
eraseToHashMap f r = M.fromList $ eraseWithLabels @c f r
newtype RMap (f :: * -> *) (ρ :: Row *) = RMap { unRMap :: Rec (Map f ρ) }
newtype RMap2 (f :: * -> *) (g :: * -> *) (ρ :: Row *) = RMap2 { unRMap2 :: Rec (Map f (Map g ρ)) }
map :: forall c f r. Forall r c => (forall a. c a => a -> f a) -> Rec r -> Rec (Map f r)
map f = unRMap . metamorph @_ @r @c @(,) @Rec @(RMap f) @f Proxy doNil doUncons doCons
where
doNil _ = RMap empty
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, HasType ℓ τ ρ)
=> Label ℓ -> Rec ρ -> (Rec (ρ .- ℓ), f τ)
doUncons l = second f . lazyUncons l
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ)
=> Label ℓ -> (RMap f ρ, f τ) -> RMap f (Extend ℓ τ ρ)
doCons l (RMap r, v) = RMap (extend l v r)
\\ mapExtendSwap @f @ℓ @τ @ρ
newtype RFMap (g :: k1 -> k2) (ϕ :: Row (k2 -> *)) (ρ :: Row k1) = RFMap { unRFMap :: Rec (Ap ϕ (Map g ρ)) }
newtype RecAp (ϕ :: Row (k -> *)) (ρ :: Row k) = RecAp (Rec (Ap ϕ ρ))
newtype App (f :: k -> *) (a :: k) = App (f a)
mapF :: forall k c g (ϕ :: Row (k -> *)) (ρ :: Row k). BiForall ϕ ρ c
=> (forall h a. (c h a) => h a -> h (g a))
-> Rec (Ap ϕ ρ)
-> Rec (Ap ϕ (Map g ρ))
mapF f = unRFMap . biMetamorph @_ @_ @ϕ @ρ @c @(,) @RecAp @(RFMap g) @App Proxy doNil doUncons doCons . RecAp
where
doNil _ = RFMap empty
doUncons :: forall ℓ f τ ϕ ρ. (KnownSymbol ℓ, c f τ, HasType ℓ f ϕ, HasType ℓ τ ρ)
=> Label ℓ -> RecAp ϕ ρ -> (RecAp (ϕ .- ℓ) (ρ .- ℓ), App f τ)
doUncons l (RecAp r) = bimap RecAp App $ lazyUncons l r
\\ apHas @ℓ @f @ϕ @τ @ρ
doCons :: forall ℓ f τ ϕ ρ. (KnownSymbol ℓ, c f τ)
=> Label ℓ -> (RFMap g ϕ ρ, App f τ) -> RFMap g (Extend ℓ f ϕ) (Extend ℓ τ ρ)
doCons l (RFMap r, App v) = RFMap (extend l (f @f @τ v) r)
\\ mapExtendSwap @g @ℓ @τ @ρ
\\ apExtendSwap @ℓ @f @ϕ @(g τ) @(Map g ρ)
map' :: forall f r. FreeForall r => (forall a. a -> f a) -> Rec r -> Rec (Map f r)
map' = map @Unconstrained1
transform :: forall c r (f :: * -> *) (g :: * -> *). Forall r c => (forall a. c a => f a -> g a) -> Rec (Map f r) -> Rec (Map g r)
transform f = unRMap . metamorph @_ @r @c @(,) @(RMap f) @(RMap g) @f Proxy doNil doUncons doCons . RMap
where
doNil _ = RMap empty
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, HasType ℓ τ ρ)
=> Label ℓ -> RMap f ρ -> (RMap f (ρ .- ℓ), f τ)
doUncons l (RMap r) = first RMap $ lazyUncons l r
\\ mapHas @f @ℓ @τ @ρ
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ)
=> Label ℓ -> (RMap g ρ, f τ) -> RMap g (Extend ℓ τ ρ)
doCons l (RMap r, v) = RMap (extend l (f v) r)
\\ mapExtendSwap @g @ℓ @τ @ρ
transform' :: forall r (f :: * -> *) (g :: * -> *). FreeForall r => (forall a. f a -> g a) -> Rec (Map f r) -> Rec (Map g r)
transform' = transform @Unconstrained1 @r
data RecMapPair (f :: * -> *) (g :: * -> *) (ρ :: Row *) = RecMapPair (Rec (Map f ρ)) (Rec (Map g ρ))
zipTransform :: forall c r (f :: * -> *) (g :: * -> *) (h :: * -> *) .
Forall r c => (forall a. c a => f a -> g a -> h a) -> Rec (Map f r) -> Rec (Map g r) -> Rec (Map h r)
zipTransform f x y = unRMap $ metamorph @_ @r @c @(,) @(RecMapPair f g) @(RMap h) @h Proxy doNil doUncons doCons $ RecMapPair x y
where
doNil _ = RMap empty
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, HasType ℓ τ ρ)
=> Label ℓ -> RecMapPair f g ρ -> (RecMapPair f g (ρ .- ℓ), h τ)
doUncons l (RecMapPair x y) = (RecMapPair (lazyRemove l x) (lazyRemove l y), f (x .! l) (y .! l))
\\ mapHas @f @ℓ @τ @ρ
\\ mapHas @g @ℓ @τ @ρ
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ)
=> Label ℓ -> (RMap h ρ, h τ) -> RMap h (Extend ℓ τ ρ)
doCons l (RMap r, h) = RMap (extend l h r)
\\ mapExtendSwap @h @ℓ @τ @ρ
zipTransform' :: forall r (f :: * -> *) (g :: * -> *) (h :: * -> *) .
FreeForall r => (forall a. f a -> g a -> h a) -> Rec (Map f r) -> Rec (Map g r) -> Rec (Map h r)
zipTransform' = zipTransform @Unconstrained1 @r
traverse :: forall c f r. (Forall r c, Applicative f) => (forall a. c a => a -> f a) -> Rec r -> f (Rec r)
traverse f = sequence' @f @r @c . map @c @f @r f
traverseMap :: forall c (f :: * -> *) (g :: * -> *) (h :: * -> *) r.
(Forall r c, Applicative f) => (forall a. c a => g a -> f (h a)) -> Rec (Map g r) -> f (Rec (Map h r))
traverseMap f =
sequence' @f @(Map h r) @(IsA c h) .
uncompose' @c @f @h @r .
transform @c @r @g @(Compose f h) (Compose . f)
\\ mapForall @h @r @c
sequence' :: forall f r c. (Forall r c, Applicative f)
=> Rec (Map f r) -> f (Rec r)
sequence' = getCompose . metamorph @_ @r @c @(,) @(RMap f) @(Compose f Rec) @f Proxy doNil doUncons doCons . RMap
where
doNil _ = Compose (pure empty)
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, HasType ℓ τ ρ)
=> Label ℓ -> RMap f ρ -> (RMap f (ρ .- ℓ), f τ)
doUncons l (RMap r) = first RMap $ lazyUncons l r
\\ mapHas @f @ℓ @τ @ρ
doCons l (Compose fr, fv) = Compose $ extend l <$> fv <*> fr
sequence :: forall f r. (Applicative f, FreeForall r)
=> Rec (Map f r) -> f (Rec r)
sequence = sequence' @_ @_ @Unconstrained1
distribute :: forall f r. (FreeForall r, Functor f) => f (Rec r) -> Rec (Map f r)
distribute = unRMap . metamorph @_ @r @Unconstrained1 @(,) @(Compose f Rec) @(RMap f) @f Proxy doNil doUncons doCons . Compose
where
doNil _ = RMap empty
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, HasType ℓ τ ρ)
=> Label ℓ -> Compose f Rec ρ -> (Compose f Rec (ρ .- ℓ), f τ)
doUncons l (Compose fr) = (Compose $ lazyRemove l <$> fr, (.! l) <$> fr)
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ)
=> Label ℓ -> (RMap f ρ, f τ) -> RMap f (Extend ℓ τ ρ)
doCons l (RMap r, fv) = RMap (extend l fv r)
\\ mapExtendSwap @f @ℓ @τ @ρ
compose' :: forall c (f :: * -> *) (g :: * -> *) (r :: Row *) . Forall r c
=> Rec (Map f (Map g r)) -> Rec (Map (Compose f g) r)
compose' = unRMap . metamorph @_ @r @c @(,) @(RMap2 f g) @(RMap (Compose f g)) @(Compose f g) Proxy doNil doUncons doCons . RMap2
where
doNil _ = RMap empty
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, HasType ℓ τ ρ)
=> Label ℓ -> RMap2 f g ρ -> (RMap2 f g (ρ .- ℓ), Compose f g τ)
doUncons l (RMap2 r) = bimap RMap2 Compose $ lazyUncons l r
\\ mapHas @f @ℓ @(g τ) @(Map g ρ)
\\ mapHas @g @ℓ @τ @ρ
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ)
=> Label ℓ -> (RMap (Compose f g) ρ, Compose f g τ) -> RMap (Compose f g) (Extend ℓ τ ρ)
doCons l (RMap r, v) = RMap $ extend l v r
\\ mapExtendSwap @(Compose f g) @ℓ @τ @ρ
compose :: forall (f :: * -> *) (g :: * -> *) r . FreeForall r
=> Rec (Map f (Map g r)) -> Rec (Map (Compose f g) r)
compose = compose' @Unconstrained1 @f @g @r
uncompose' :: forall c (f :: * -> *) (g :: * -> *) r . Forall r c
=> Rec (Map (Compose f g) r) -> Rec (Map f (Map g r))
uncompose' = unRMap2 . metamorph @_ @r @c @(,) @(RMap (Compose f g)) @(RMap2 f g) @(Compose f g) Proxy doNil doUncons doCons . RMap
where
doNil _ = RMap2 empty
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, HasType ℓ τ ρ)
=> Label ℓ -> RMap (Compose f g) ρ -> (RMap (Compose f g) (ρ .- ℓ), Compose f g τ)
doUncons l (RMap r) = first RMap $ lazyUncons l r
\\ mapHas @(Compose f g) @ℓ @τ @ρ
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ)
=> Label ℓ -> (RMap2 f g ρ, Compose f g τ) -> RMap2 f g (Extend ℓ τ ρ)
doCons l (RMap2 r, Compose v) = RMap2 $ extend l v r
\\ mapExtendSwap @f @ℓ @(g τ) @(Map g ρ)
\\ mapExtendSwap @g @ℓ @τ @ρ
uncompose :: forall (f :: * -> *) (g :: * -> *) r . FreeForall r
=> Rec (Map (Compose f g) r) -> Rec (Map f (Map g r))
uncompose = uncompose' @Unconstrained1 @f @g @r
coerceRec :: forall r1 r2. BiForall r1 r2 Coercible => Rec r1 -> Rec r2
coerceRec = unsafeCoerce
newtype RecPair (ρ1 :: Row *) (ρ2 :: Row *) = RecPair (Rec ρ1, Rec ρ2)
newtype RZipPair (ρ1 :: Row *) (ρ2 :: Row *) = RZipPair { unRZipPair :: Rec (Zip ρ1 ρ2) }
zip :: forall r1 r2. FreeBiForall r1 r2 => Rec r1 -> Rec r2 -> Rec (Zip r1 r2)
zip r1 r2 = unRZipPair $ biMetamorph @_ @_ @r1 @r2 @Unconstrained2 @(,) @RecPair @RZipPair @(,) Proxy doNil doUncons doCons $ RecPair (r1, r2)
where
doNil _ = RZipPair empty
doUncons l (RecPair (r1, r2)) = (RecPair (lazyRemove l r1, lazyRemove l r2), (r1 .! l, r2 .! l))
doCons :: forall ℓ τ1 τ2 ρ1 ρ2. (KnownSymbol ℓ)
=> Label ℓ -> (RZipPair ρ1 ρ2, (τ1, τ2)) -> RZipPair (Extend ℓ τ1 ρ1) (Extend ℓ τ2 ρ2)
doCons l (RZipPair r, vs) = RZipPair $ extend l vs r
\\ zipExtendSwap @ℓ @τ1 @ρ1 @τ2 @ρ2
default' :: forall c ρ. (Forall ρ c, AllUniqueLabels ρ) => (forall a. c a => a) -> Rec ρ
default' v = runIdentity $ defaultA @c $ pure v
defaultA :: forall c f ρ. (Applicative f, Forall ρ c, AllUniqueLabels ρ)
=> (forall a. c a => f a) -> f (Rec ρ)
defaultA v = fromLabelsA @c $ pure v
fromLabels :: forall c ρ. (Forall ρ c, AllUniqueLabels ρ)
=> (forall l a. (KnownSymbol l, c a) => Label l -> a) -> Rec ρ
fromLabels f = runIdentity $ fromLabelsA @c $ (pure .) f
fromLabelsA :: forall c f ρ. (Applicative f, Forall ρ c, AllUniqueLabels ρ)
=> (forall l a. (KnownSymbol l, c a) => Label l -> f a) -> f (Rec ρ)
fromLabelsA mk = getCompose $ metamorph @_ @ρ @c @Const @(Const ()) @(Compose f Rec) @Proxy Proxy doNil doUncons doCons (Const ())
where doNil _ = Compose $ pure empty
doUncons _ _ = Const $ Const ()
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ)
=> Label ℓ -> Const (Compose f Rec ρ) (Proxy τ) -> Compose f Rec (Extend ℓ τ ρ)
doCons l (Const (Compose r)) = Compose $ extend l <$> mk @ℓ @τ l <*> r
fromLabelsMapA :: forall c f g ρ. (Applicative f, Forall ρ c, AllUniqueLabels ρ)
=> (forall l a. (KnownSymbol l, c a) => Label l -> f (g a)) -> f (Rec (Map g ρ))
fromLabelsMapA f = fromLabelsA @(IsA c g) @f @(Map g ρ) inner
\\ mapForall @g @ρ @c
\\ uniqueMap @g @ρ
where inner :: forall l a. (KnownSymbol l, IsA c g a) => Label l -> f a
inner l = case as @c @g @a of As -> f l
toDynamicMap :: Forall r Typeable => Rec r -> HashMap Text Dynamic
toDynamicMap = eraseToHashMap @Typeable @_ @Text @Dynamic toDyn
fromDynamicMap :: (AllUniqueLabels r, Forall r Typeable)
=> HashMap Text Dynamic -> Maybe (Rec r)
fromDynamicMap m = fromLabelsA @Typeable
$ \ (toKey -> k) -> M.lookup k m >>= fromDynamic
instance GenericRec r => G.Generic (Rec r) where
type Rep (Rec r) =
G.D1 ('G.MetaData "Rec" "Data.Row.Records" "row-types" 'False)
(G.C1 ('G.MetaCons "Rec" 'G.PrefixI 'True)
(RepRec r))
from = G.M1 . G.M1 . fromRec
to = toRec . G.unM1 . G.unM1
class GenericRec r where
type RepRec (r :: Row *) :: * -> *
fromRec :: Rec r -> RepRec r x
toRec :: RepRec r x -> Rec r
instance GenericRec Empty where
type RepRec (R '[]) = G.U1
fromRec _ = G.U1
toRec _ = empty
instance KnownSymbol name => GenericRec (R '[name :-> t]) where
type RepRec (R (name :-> t ': '[])) = G.S1
('G.MetaSel ('Just name) 'G.NoSourceUnpackedness 'G.NoSourceStrictness 'G.DecidedLazy)
(G.Rec0 t)
fromRec (_ :== a) = G.M1 (G.K1 a)
toRec (G.M1 (G.K1 a)) = (Label @name) :== a
instance
( r ~ (name' :-> t' ': r'), GenericRec (R r)
, KnownSymbol name, Extend name t ('R r) ≈ 'R (name :-> t ': r)
) => GenericRec (R (name :-> t ': (name' :-> t' ': r'))) where
type RepRec (R (name :-> t ': (name' :-> t' ': r'))) = (G.S1
('G.MetaSel ('Just name) 'G.NoSourceUnpackedness 'G.NoSourceStrictness 'G.DecidedLazy)
(G.Rec0 t)) G.:*: RepRec (R (name' :-> t' ': r'))
fromRec r = G.M1 (G.K1 (r .! Label @name)) G.:*: fromRec (lazyRemove @name Label r)
toRec (G.M1 (G.K1 a) G.:*: r) = extend @_ @name @('R (name' :-> t' ': r')) Label a (toRec r)
type family NativeRow t where
NativeRow t = NativeRowG (G.Rep t)
type family NativeRowG t where
NativeRowG (G.M1 G.D m cs) = NativeRowG cs
NativeRowG (G.M1 G.C m cs) = NativeRowG cs
NativeRowG G.U1 = Empty
NativeRowG (l G.:*: r) = NativeRowG l .+ NativeRowG r
NativeRowG (G.M1 G.S ('G.MetaSel ('Just name) p s l) (G.Rec0 t)) = name .== t
class FromNativeG a where
fromNative' :: a x -> Rec (NativeRowG a)
instance FromNativeG cs => FromNativeG (G.D1 m cs) where
fromNative' (G.M1 xs) = fromNative' xs
instance FromNativeG cs => FromNativeG (G.C1 m cs) where
fromNative' (G.M1 xs) = fromNative' xs
instance FromNativeG G.U1 where
fromNative' G.U1 = empty
instance KnownSymbol name => FromNativeG (G.S1 ('G.MetaSel ('Just name) p s l) (G.Rec0 t)) where
fromNative' (G.M1 (G.K1 x)) = (Label @name) .== x
instance (FromNativeG l, FromNativeG r, FreeForall (NativeRowG l)) => FromNativeG (l G.:*: r) where
fromNative' (x G.:*: y) = fromNative' @l x .+ fromNative' @r y
type FromNative t = (G.Generic t, FromNativeG (G.Rep t))
fromNative :: FromNative t => t -> Rec (NativeRow t)
fromNative = fromNative' . G.from
class ToNativeG a where
toNative' :: Rec (NativeRowG a) -> a x
instance ToNativeG cs => ToNativeG (G.D1 m cs) where
toNative' xs = G.M1 $ toNative' xs
instance ToNativeG cs => ToNativeG (G.C1 m cs) where
toNative' xs = G.M1 $ toNative' xs
instance ToNativeG G.U1 where
toNative' _ = G.U1
instance (KnownSymbol name) => ToNativeG (G.S1 ('G.MetaSel ('Just name) p s l) (G.Rec0 t)) where
toNative' r = G.M1 $ G.K1 $ r .! (Label @name)
instance (ToNativeG l, ToNativeG r, Disjoint (NativeRowG l) (NativeRowG r))
=> ToNativeG (l G.:*: r) where
toNative' r = toNative' r1 G.:*: toNative' r2
where
(r1 :: Rec (NativeRowG l)) :+ (r2 :: Rec (NativeRowG r)) = r
type ToNative t = (G.Generic t, ToNativeG (G.Rep t))
toNative :: ToNative t => Rec (NativeRow t) -> t
toNative = G.to . toNative'
class ToNativeGeneralG a ρ where
toNativeGeneral' :: Rec ρ -> a x
instance ToNativeGeneralG cs ρ => ToNativeGeneralG (G.D1 m cs) ρ where
toNativeGeneral' xs = G.M1 $ toNativeGeneral' xs
instance ToNativeGeneralG cs ρ => ToNativeGeneralG (G.C1 m cs) ρ where
toNativeGeneral' xs = G.M1 $ toNativeGeneral' xs
instance ToNativeGeneralG G.U1 ρ where
toNativeGeneral' _ = G.U1
instance (KnownSymbol name, ρ .! name ≈ t)
=> ToNativeGeneralG (G.S1 ('G.MetaSel ('Just name) p s l) (G.Rec0 t)) ρ where
toNativeGeneral' r = G.M1 $ G.K1 $ r .! (Label @name)
instance (ToNativeGeneralG l ρ, ToNativeGeneralG r ρ)
=> ToNativeGeneralG (l G.:*: r) ρ where
toNativeGeneral' r = toNativeGeneral' r G.:*: toNativeGeneral' r
type ToNativeGeneral t ρ = (G.Generic t, ToNativeGeneralG (G.Rep t) ρ)
toNativeGeneral :: ToNativeGeneral t ρ => Rec ρ -> t
toNativeGeneral = G.to . toNativeGeneral'
instance {-# OVERLAPPING #-}
( KnownSymbol name
, r' .! name ≈ b
, r .! name ≈ a
, r' ~ Modify name b r
, r ~ Modify name a r')
=> HasField name (Rec r) (Rec r') a b where
field = focus (Label @name)
{-# INLINE field #-}
instance {-# OVERLAPPING #-}
( KnownSymbol name
, r .! name ≈ a
, r ~ Modify name a r)
=> HasField' name (Rec r) a where
field' = focus (Label @name)
{-# INLINE field' #-}