{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Row.Variants
(
Label(..)
, KnownSymbol, AllUniqueLabels, WellBehaved
, Var, Row, Empty, type (≈)
, HasType, pattern IsJust, singleton, unSingleton
, fromLabels, fromLabelsMap
, type (.\), Lacks, type (.\/), diversify, extend, type (.+)
, update, focus, Modify, rename, Rename
, impossible, trial, trial', multiTrial, view
, restrict, split
, type (.!), type (.-), type (.\\), type (.==)
, toNative, fromNative, fromNativeGeneral
, ToNative, FromNative, FromNativeGeneral
, NativeRow
, Map, map, map', transform, transform'
, Forall, erase, eraseWithLabels, eraseZipGeneral, eraseZip
, traverse, traverseMap
, sequence
, compose, uncompose
, labels
, eraseSingle, mapSingle, eraseZipSingle
, coerceVar
)
where
import Prelude hiding (map, sequence, traverse, zip)
import Control.Applicative
import Control.DeepSeq (NFData(..), deepseq)
import Data.Bifunctor (Bifunctor(..))
import Data.Coerce
import Data.Constraint (Constraint)
import Data.Functor.Compose
import Data.Functor.Identity
import Data.Functor.Product
import Data.Generics.Sum.Constructors (AsConstructor(..), AsConstructor'(..))
import Data.Maybe (fromMaybe)
import Data.Profunctor (Choice(..), Profunctor(..))
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
data Var (r :: Row *) where
OneOf :: Text -> HideType -> Var r
instance Forall r Show => Show (Var r) where
show v = (\ (x, y) -> "{" ++ x ++ "=" ++ y ++ "}") $ eraseWithLabels @Show show v
instance Forall r Eq => Eq (Var r) where
r == r' = fromMaybe False $ eraseZip @Eq (==) r r'
instance (Forall r Eq, Forall r Ord) => Ord (Var r) where
compare :: Var r -> Var r -> Ordering
compare = eraseZipGeneral @Ord @r @Ordering @Text $ \case
(Left (_, x, y)) -> compare x y
(Right ((s1, _), (s2, _))) -> compare s1 s2
instance Forall r NFData => NFData (Var r) where
rnf r = getConst $ metamorph @_ @r @NFData @Either @Var @(Const ()) @Identity Proxy empty doUncons doCons r
where empty = const $ Const ()
doUncons l = second Identity . flip trial l
doCons _ x = deepseq x $ Const ()
impossible :: Var Empty -> a
impossible _ = error "Impossible! Somehow, a variant of nothing was produced."
singleton :: KnownSymbol l => Label l -> a -> Var (l .== a)
singleton = IsJust
unSingleton :: forall l a. KnownSymbol l => Var (l .== a) -> (Label l, a)
unSingleton (OneOf _ (HideType x)) = (l, unsafeCoerce x) where l = Label @l
pattern IsJust :: forall l r. (AllUniqueLabels r, KnownSymbol l) => Label l -> r .! l -> Var r
pattern IsJust l a <- (isJustHelper @l -> (l, Just a)) where
IsJust (toKey -> l) = OneOf l . HideType
isJustHelper :: forall l r. KnownSymbol l => Var r -> (Label l, Maybe (r .! l))
isJustHelper v = (l, view l v) where l = Label @l
diversify :: forall r' r. Var r -> Var (r .\/ r')
diversify = unsafeCoerce
extend :: forall a l r. KnownSymbol l => Label l -> Var r -> Var (Extend l a r)
extend _ = unsafeCoerce
update :: (KnownSymbol l, r .! l ≈ a) => Label l -> a -> Var r -> Var r
update (toKey -> l') a (OneOf l x) = OneOf l $ if l == l' then HideType a else x
focus :: forall l r r' a b p f.
( AllUniqueLabels r
, AllUniqueLabels r'
, KnownSymbol l
, r .! l ≈ a
, r' .! l ≈ b
, r' ≈ (r .- l) .\/ (l .== b)
, Applicative f
, Choice p
) => Label l -> p a (f b) -> p (Var r) (f (Var r'))
focus (toKey -> l) =
dimap unwrap rewrap . left'
where
unwrap :: Var r -> Either a (Var r')
unwrap (OneOf l' (HideType x))
| l == l' = Left (unsafeCoerce x)
| otherwise = Right (OneOf l' (HideType x))
rewrap :: Either (f b) (Var r') -> f (Var r')
rewrap = either (fmap $ OneOf l . HideType) pure
rename :: (KnownSymbol l, KnownSymbol l') => Label l -> Label l' -> Var r -> Var (Rename l l' r)
rename (toKey -> l1) (toKey -> l2) (OneOf l x) = OneOf (if l == l1 then l2 else l) x
trial :: KnownSymbol l => Var r -> Label l -> Either (Var (r .- l)) (r .! l)
trial (OneOf l (HideType x)) (toKey -> l') = if l == l' then Right (unsafeCoerce x) else Left (OneOf l (HideType x))
trial' :: KnownSymbol l => Var r -> Label l -> Maybe (r .! l)
trial' = (either (const Nothing) Just .) . trial
multiTrial :: forall x y. (AllUniqueLabels x, Forall (y .\\ x) Unconstrained1) => Var y -> Either (Var (y .\\ x)) (Var x)
multiTrial (OneOf l x) = if l `elem` labels @(y .\\ x) @Unconstrained1 then Left (OneOf l x) else Right (OneOf l x)
view :: KnownSymbol l => Label l -> Var r -> Maybe (r .! l)
view = flip trial'
split :: forall s r. (WellBehaved s, Subset s r) => Var r -> Either (Var (r .\\ s)) (Var s)
split (OneOf l a) | l `elem` labels @s @Unconstrained1 = Right $ OneOf l a
| otherwise = Left $ OneOf l a
restrict :: forall r r'. (WellBehaved r, Subset r r') => Var r' -> Maybe (Var r)
restrict = either (pure Nothing) Just . split
erase :: forall c ρ b. Forall ρ c => (forall a. c a => a -> b) -> Var ρ -> b
erase f = snd @String . eraseWithLabels @c f
eraseWithLabels :: forall c ρ s b. (Forall ρ c, IsString s) => (forall a. c a => a -> b) -> Var ρ -> (s,b)
eraseWithLabels f = getConst . metamorph @_ @ρ @c @Either @Var @(Const (s,b)) @Identity Proxy impossible doUncons doCons
where doUncons l = second Identity . flip trial l
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ)
=> Label ℓ -> Either (Const (s,b) ρ) (Identity τ) -> Const (s,b) (Extend ℓ τ ρ)
doCons _ (Left (Const c)) = Const c
doCons l (Right (Identity x)) = Const (show' l, f x)
data ErasedVal c s = forall y. c y => ErasedVal (s, y)
data ErasePair c s ρ = ErasePair (Either (ErasedVal c s) (Var ρ)) (Either (ErasedVal c s) (Var ρ))
eraseZipGeneral
:: forall c ρ b s. (Forall ρ c, IsString s)
=> (forall x y. (c x, c y) => Either (s, x, x) ((s, x), (s, y)) -> b)
-> Var ρ -> Var ρ -> b
eraseZipGeneral f x y = getConst $ metamorph @_ @ρ @c @Either @(ErasePair c s) @(Const b) @(Const b) Proxy doNil doUncons doCons (ErasePair (Right x) (Right y))
where
doNil (ErasePair (Left (ErasedVal a)) (Left (ErasedVal b))) =
Const $ f $ Right (a, b)
doNil (ErasePair (Right x) _) = impossible x
doNil (ErasePair _ (Right y)) = impossible y
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, HasType ℓ τ ρ)
=> Label ℓ -> ErasePair c s ρ -> Either (ErasePair c s (ρ .- ℓ)) (Const b τ)
doUncons _ (ErasePair (Left (ErasedVal a)) (Left (ErasedVal b))) =
Right $ Const $ f $ Right (a, b)
doUncons l (ErasePair (Right x) (Left eb)) = case (trial x l, eb) of
(Right a, ErasedVal b) -> Right $ Const $ f $ Right ((show' l, a), b)
(Left x', _) -> Left $ ErasePair (Right x') (Left eb)
doUncons l (ErasePair (Left ea) (Right y)) = case (ea, trial y l) of
(ErasedVal a, Right b) -> Right $ Const $ f $ Right (a, (show' l, b))
(_, Left x') -> Left $ ErasePair (Left ea) (Right x')
doUncons l (ErasePair (Right x) (Right y)) = case (trial x l, trial y l) of
(Right (a :: x), Right b) -> Right $ Const $ f @x @x $ Left (show' l, a, b)
(Right a, Left y') -> Left $ ErasePair (Left $ ErasedVal (show' l, a)) (Right y')
(Left x', Right b) -> Left $ ErasePair (Right x') (Left $ ErasedVal (show' l, b))
(Left x', Left y') -> Left $ ErasePair (Right x') (Right y')
doCons _ (Left (Const b)) = Const b
doCons _ (Right (Const b)) = Const b
eraseZip :: forall c ρ b. Forall ρ c => (forall a. c a => a -> a -> b) -> Var ρ -> Var ρ -> Maybe b
eraseZip f = eraseZipGeneral @c @ρ @(Maybe b) @Text $ \case
Left (_,x,y) -> Just (f x y)
_ -> Nothing
newtype VMap (f :: * -> *) (ρ :: Row *) = VMap { unVMap :: Var (Map f ρ) }
newtype VMap2 (f :: * -> *) (g :: * -> *) (ρ :: Row *) = VMap2 { unVMap2 :: Var (Map f (Map g ρ)) }
map :: forall c f r. Forall r c => (forall a. c a => a -> f a) -> Var r -> Var (Map f r)
map f = unVMap . metamorph @_ @r @c @Either @Var @(VMap f) @Identity Proxy impossible doUncons doCons
where
doUncons l = second Identity . flip trial l
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, AllUniqueLabels (Extend ℓ τ ρ))
=> Label ℓ -> Either (VMap f ρ) (Identity τ) -> VMap f (Extend ℓ τ ρ)
doCons l (Left (VMap v)) = VMap $ extend @(f τ) l v
\\ mapExtendSwap @f @ℓ @τ @ρ
doCons l (Right (Identity x)) = VMap $ IsJust l (f x)
\\ mapExtendSwap @f @ℓ @τ @ρ
\\ extendHas @ℓ @(f τ) @(Map f ρ)
\\ uniqueMap @f @(Extend ℓ τ ρ)
map' :: forall f r. FreeForall r => (forall a. a -> f a) -> Var r -> Var (Map f r)
map' = map @Unconstrained1
transform :: forall c r (f :: * -> *) (g :: * -> *). Forall r c => (forall a. c a => f a -> g a) -> Var (Map f r) -> Var (Map g r)
transform f = unVMap . metamorph @_ @r @c @Either @(VMap f) @(VMap g) @f Proxy doNil doUncons doCons . VMap
where
doNil = impossible . unVMap
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, HasType ℓ τ ρ)
=> Label ℓ -> VMap f ρ -> Either (VMap f (ρ .- ℓ)) (f τ)
doUncons l = first VMap . flip trial l . unVMap
\\ mapHas @f @ℓ @τ @ρ
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, AllUniqueLabels (Extend ℓ τ ρ))
=> Label ℓ -> Either (VMap g ρ) (f τ) -> VMap g (Extend ℓ τ ρ)
doCons l (Left (VMap v)) = VMap $ extend @(g τ) l v
\\ mapExtendSwap @g @ℓ @τ @ρ
doCons l (Right x) = VMap $ IsJust l (f x)
\\ mapExtendSwap @g @ℓ @τ @ρ
\\ extendHas @ℓ @(g τ) @(Map g ρ)
\\ uniqueMap @g @(Extend ℓ τ ρ)
transform' :: forall r (f :: * -> *) (g :: * -> *) . FreeForall r => (forall a. f a -> g a) -> Var (Map f r) -> Var (Map g r)
transform' = transform @Unconstrained1 @r
traverse :: forall c f r. (Forall r c, Applicative f) => (forall a. c a => a -> f a) -> Var r -> f (Var 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)) -> Var (Map g r) -> f (Var (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) => Var (Map f r) -> f (Var r)
sequence' = getCompose . metamorph @_ @r @c @Either @(VMap f) @(Compose f Var) @f Proxy doNil doUncons doCons . VMap
where
doNil = impossible . unVMap
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, HasType ℓ τ ρ)
=> Label ℓ -> VMap f ρ -> Either (VMap f (ρ .- ℓ)) (f τ)
doUncons l = first VMap . flip trial l . unVMap
\\ mapHas @f @ℓ @τ @ρ
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, AllUniqueLabels (Extend ℓ τ ρ))
=> Label ℓ -> Either (Compose f Var ρ) (f τ) -> Compose f Var (Extend ℓ τ ρ)
doCons l (Left (Compose v)) = Compose $ extend @τ l <$> v
doCons l (Right fx) = Compose $ IsJust l <$> fx
\\ extendHas @ℓ @τ @ρ
sequence :: forall f r. (FreeForall r, Applicative f) => Var (Map f r) -> f (Var r)
sequence = sequence' @f @r @Unconstrained1
compose :: forall (f :: * -> *) (g :: * -> *) r . FreeForall r => Var (Map f (Map g r)) -> Var (Map (Compose f g) r)
compose = unVMap . metamorph @_ @r @Unconstrained1 @Either @(VMap2 f g) @(VMap (Compose f g)) @(Compose f g) Proxy doNil doUncons doCons . VMap2
where
doNil = impossible . unVMap2
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, HasType ℓ τ ρ)
=> Label ℓ -> VMap2 f g ρ -> Either (VMap2 f g (ρ .- ℓ)) (Compose f g τ)
doUncons l = bimap VMap2 Compose . flip trial l . unVMap2
\\ mapHas @f @ℓ @(g τ) @(Map g ρ)
\\ mapHas @g @ℓ @τ @ρ
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, AllUniqueLabels (Extend ℓ τ ρ))
=> Label ℓ -> Either (VMap (Compose f g) ρ) (Compose f g τ) -> VMap (Compose f g) (Extend ℓ τ ρ)
doCons l (Left (VMap v)) = VMap $ extend @(Compose f g τ) l v
\\ mapExtendSwap @(Compose f g) @ℓ @τ @ρ
doCons l (Right x) = VMap $ IsJust l x
\\ mapExtendSwap @(Compose f g) @ℓ @τ @ρ
\\ extendHas @ℓ @((Compose f g) τ) @(Map (Compose f g) ρ)
\\ uniqueMap @(Compose f g) @(Extend ℓ τ ρ)
uncompose' :: forall c (f :: * -> *) (g :: * -> *) r . Forall r c => Var (Map (Compose f g) r) -> Var (Map f (Map g r))
uncompose' = unVMap2 . metamorph @_ @r @c @Either @(VMap (Compose f g)) @(VMap2 f g) @(Compose f g) Proxy doNil doUncons doCons . VMap
where
doNil = impossible . unVMap
doUncons :: forall ℓ τ ρ. (KnownSymbol ℓ, HasType ℓ τ ρ)
=> Label ℓ -> VMap (Compose f g) ρ -> Either (VMap (Compose f g) (ρ .- ℓ)) (Compose f g τ)
doUncons l = first VMap . flip trial l . unVMap
\\ mapHas @(Compose f g) @ℓ @τ @ρ
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, AllUniqueLabels (Extend ℓ τ ρ))
=> Label ℓ -> Either (VMap2 f g ρ) (Compose f g τ) -> VMap2 f g (Extend ℓ τ ρ)
doCons l (Left (VMap2 v)) = VMap2 $ extend @(f (g τ)) l v
\\ mapExtendSwap @f @ℓ @(g τ) @(Map g ρ)
\\ mapExtendSwap @g @ℓ @τ @ρ
doCons l (Right (Compose x)) = VMap2 $ IsJust l x
\\ mapExtendSwap @f @ℓ @(g τ) @(Map g ρ)
\\ mapExtendSwap @g @ℓ @τ @ρ
\\ extendHas @ℓ @(f (g τ)) @(Map f (Map g ρ))
\\ uniqueMap @f @(Extend ℓ (g τ) (Map g ρ))
\\ uniqueMap @g @(Extend ℓ τ ρ)
uncompose :: forall (f :: * -> *) (g :: * -> *) r . FreeForall r => Var (Map (Compose f g) r) -> Var (Map f (Map g r))
uncompose = uncompose' @Unconstrained1 @f @g @r
coerceVar :: forall r1 r2. BiForall r1 r2 Coercible => Var r1 -> Var r2
coerceVar = unsafeCoerce
fromLabels :: forall c ρ f. (Alternative f, Forall ρ c, AllUniqueLabels ρ)
=> (forall l a. (KnownSymbol l, c a) => Label l -> f a) -> f (Var ρ)
fromLabels mk = getCompose $ metamorph @_ @ρ @c @Const @(Const ()) @(Compose f Var) @Proxy
Proxy doNil doUncons doCons (Const ())
where doNil _ = Compose $ empty
doUncons _ _ = Const $ Const ()
doCons :: forall ℓ τ ρ. (KnownSymbol ℓ, c τ, AllUniqueLabels (Extend ℓ τ ρ))
=> Label ℓ -> Const (Compose f Var ρ) (Proxy τ) -> Compose f Var (Extend ℓ τ ρ)
doCons l (Const (Compose v)) = Compose $ IsJust l <$> mk l <|> extend @τ l <$> v
\\ extendHas @ℓ @τ @ρ
fromLabelsMap :: forall c f g ρ. (Alternative f, Forall ρ c, AllUniqueLabels ρ)
=> (forall l a. (KnownSymbol l, c a) => Label l -> f (g a)) -> f (Var (Map g ρ))
fromLabelsMap f = fromLabels @(IsA c g) @(Map g ρ) @f 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
newtype VApS x (fs :: Row (* -> *)) = VApS { unVApS :: Var (ApSingle fs x) }
newtype FlipApp (x :: *) (f :: * -> *) = FlipApp (f x)
eraseSingle
:: forall (c :: (* -> *) -> Constraint) (fs :: Row (* -> *)) (x :: *) (y :: *)
. Forall fs c
=> (forall f . (c f) => f x -> y)
-> Var (ApSingle fs x)
-> y
eraseSingle f = erase @(ActsOn c x) @(ApSingle fs x) @y g
\\ apSingleForall @x @fs @c
where
g :: forall a. ActsOn c x a => a -> y
g a = case actsOn @c @x @a of As' -> f a
mapSingle
:: forall (c :: (* -> *) -> Constraint) (fs :: Row (* -> *)) (x :: *) (y :: *)
. (Forall fs c)
=> (forall f . (c f) => f x -> f y)
-> Var (ApSingle fs x)
-> Var (ApSingle fs y)
mapSingle f = unVApS . metamorph @_ @fs @c @Either @(VApS x) @(VApS y) @(FlipApp x)
Proxy doNil doUncons doCons . VApS
where
doNil = impossible . unVApS
doUncons :: forall l f fs
. ( c f, fs .! l ≈ f, KnownSymbol l)
=> Label l -> VApS x fs -> Either (VApS x (fs .- l)) (FlipApp x f)
doUncons l = bimap VApS FlipApp
. flip (trial \\ apSingleHas @x @l @f @fs) l
. unVApS
doCons :: forall l f fs. (KnownSymbol l, c f, AllUniqueLabels (Extend l f fs))
=> Label l
-> Either (VApS y fs) (FlipApp x f)
-> VApS y (Extend l f fs)
doCons l (Right (FlipApp x)) = VApS $ IsJust l (f x)
\\ apSingleExtendSwap @y @l @f @fs
\\ extendHas @l @(f y) @(ApSingle fs y)
\\ uniqueApSingle @y @(Extend l f fs)
doCons l (Left (VApS v)) = VApS $ extend @(f y) l v
\\ apSingleExtendSwap @y @l @f @fs
eraseZipSingle :: forall c fs (x :: *) (y :: *) z
. (Forall fs c)
=> (forall f. c f => f x -> f y -> z)
-> Var (ApSingle fs x) -> Var (ApSingle fs y) -> Maybe z
eraseZipSingle f x y = getConst $ metamorph @_ @fs @c @Either
@(Product (VApS x) (VApS y)) @(Const (Maybe z)) @(Const (Maybe z))
Proxy doNil doUncons doCons (Pair (VApS x) (VApS y))
where doNil :: Product (VApS x) (VApS y) Empty
-> Const (Maybe z) (Empty :: Row (* -> *))
doNil (Pair (VApS z) _) = Const (impossible z)
doUncons :: forall l f ρ
. (KnownSymbol l, c f, ρ .! l ≈ f)
=> Label l
-> Product (VApS x) (VApS y) ρ
-> Either (Product (VApS x) (VApS y) (ρ .- l))
(Const (Maybe z) f)
doUncons l (Pair (VApS r1) (VApS r2)) =
case (
trial r1 l \\ apSingleHas @x @l @f @ρ,
trial r2 l \\ apSingleHas @y @l @f @ρ
) of
(Right u, Right v) -> Right $ Const $ Just $ f @f u v
(Left us, Left vs) -> Left (Pair (VApS us) (VApS vs))
_ -> Right $ Const Nothing
doCons :: forall l (τ :: * -> *) ρ
. Label l
-> Either (Const (Maybe z) ρ) (Const (Maybe z) τ)
-> Const (Maybe z) (Extend l τ ρ)
doCons _ (Left (Const w)) = Const w
doCons _ (Right (Const w)) = Const w
instance GenericVar r => G.Generic (Var r) where
type Rep (Var r) =
G.D1 ('G.MetaData "Var" "Data.Row.Variants" "row-types" 'False) (RepVar r)
from = G.M1 . fromVar
to = toVar . G.unM1
class GenericVar r where
type RepVar (r :: Row *) :: * -> *
fromVar :: Var r -> RepVar r x
toVar :: RepVar r x -> Var r
instance GenericVar Empty where
type RepVar Empty = G.V1
fromVar = impossible
toVar = \case
instance KnownSymbol name => GenericVar (R '[name :-> t]) where
type RepVar (R (name :-> t ': '[])) = G.C1
('G.MetaCons name 'G.PrefixI 'False)
(G.S1 ('G.MetaSel 'Nothing 'G.NoSourceUnpackedness 'G.NoSourceStrictness 'G.DecidedLazy)
(G.Rec0 t))
fromVar (unSingleton -> (_, a)) = G.M1 (G.M1 (G.K1 a))
toVar (G.M1 (G.M1 (G.K1 a))) = IsJust (Label @name) a
instance
( GenericVar (R (name' :-> t' ': r'))
, KnownSymbol name, Extend name t ('R (name' :-> t' ': r')) ≈ 'R (name :-> t ': (name' :-> t' ': r'))
, AllUniqueLabels (R (name :-> t ': (name' :-> t' ': r')))
) => GenericVar (R (name :-> t ': (name' :-> t' ': r'))) where
type RepVar (R (name :-> t ': (name' :-> t' ': r'))) = (G.C1
('G.MetaCons name 'G.PrefixI 'False)
(G.S1 ('G.MetaSel 'Nothing 'G.NoSourceUnpackedness 'G.NoSourceStrictness 'G.DecidedLazy)
(G.Rec0 t))) G.:+: RepVar (R (name' :-> t' ': r'))
fromVar v = case trial @name v Label of
Left v' -> G.R1 (fromVar v')
Right a -> G.L1 (G.M1 (G.M1 (G.K1 a)))
toVar (G.L1 (G.M1 (G.M1 (G.K1 a)))) = IsJust (Label @name) a
toVar (G.R1 g) = extend @t @name @('R (name' :-> t' ': r')) Label $ toVar g
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.V1 = Empty
NativeRowG (l G.:+: r) = NativeRowG l .+ NativeRowG r
NativeRowG (G.C1 ('G.MetaCons name fixity sels) (G.S1 m (G.Rec0 t))) = name .== t
class ToNativeG a where
toNative' :: Var (NativeRowG a) -> a x
instance ToNativeG cs => ToNativeG (G.D1 m cs) where
toNative' = G.M1 . toNative'
instance ToNativeG G.V1 where
toNative' = impossible
instance (KnownSymbol name)
=> ToNativeG (G.C1 ('G.MetaCons name fixity sels)
(G.S1 m (G.Rec0 t))) where
toNative' = G.M1 . G.M1 . G.K1 . snd . unSingleton
instance ( ToNativeG l, ToNativeG r, (NativeRowG l .+ NativeRowG r) .\\ NativeRowG r ≈ NativeRowG l
, AllUniqueLabels (NativeRowG r), Forall (NativeRowG l) Unconstrained1)
=> ToNativeG (l G.:+: r) where
toNative' v = case multiTrial @(NativeRowG r) @(NativeRowG (l G.:+: r)) v of
Left v' -> G.L1 $ toNative' v'
Right v' -> G.R1 $ toNative' v'
type ToNative t = (G.Generic t, ToNativeG (G.Rep t))
toNative :: ToNative t => Var (NativeRow t) -> t
toNative = G.to . toNative'
class FromNativeG a where
fromNative' :: a x -> Var (NativeRowG a)
instance FromNativeG cs => FromNativeG (G.D1 m cs) where
fromNative' (G.M1 v) = fromNative' v
instance FromNativeG G.V1 where
fromNative' = \ case
instance KnownSymbol name
=> FromNativeG (G.C1 ('G.MetaCons name fixity sels)
(G.S1 m (G.Rec0 t))) where
fromNative' (G.M1 (G.M1 (G.K1 x))) = IsJust (Label @name) x
instance (FromNativeG l, FromNativeG r) => FromNativeG (l G.:+: r) where
fromNative' (G.L1 x) = unsafeCoerce $ fromNative' @l x
fromNative' (G.R1 y) = unsafeCoerce $ fromNative' @r y
type FromNative t = (G.Generic t, FromNativeG (G.Rep t))
fromNative :: FromNative t => t -> Var (NativeRow t)
fromNative = fromNative' . G.from
class FromNativeGeneralG a ρ where
fromNativeGeneral' :: a x -> Var ρ
instance FromNativeGeneralG cs ρ => FromNativeGeneralG (G.D1 m cs) ρ where
fromNativeGeneral' (G.M1 v) = fromNativeGeneral' v
instance FromNativeGeneralG G.V1 ρ where
fromNativeGeneral' = \ case
instance (KnownSymbol name, ρ .! name ≈ t, AllUniqueLabels ρ)
=> FromNativeGeneralG (G.C1 ('G.MetaCons name fixity sels)
(G.S1 m (G.Rec0 t))) ρ where
fromNativeGeneral' (G.M1 (G.M1 (G.K1 x))) = IsJust (Label @name) x
instance (FromNativeGeneralG l ρ, FromNativeGeneralG r ρ)
=> FromNativeGeneralG (l G.:+: r) ρ where
fromNativeGeneral' (G.L1 x) = unsafeCoerce $ fromNativeGeneral' @l @ρ x
fromNativeGeneral' (G.R1 y) = unsafeCoerce $ fromNativeGeneral' @r @ρ y
type FromNativeGeneral t ρ = (G.Generic t, FromNativeGeneralG (G.Rep t) ρ)
fromNativeGeneral :: FromNativeGeneral t ρ => t -> Var ρ
fromNativeGeneral = fromNativeGeneral' . G.from
instance {-# OVERLAPPING #-}
( AllUniqueLabels r
, AllUniqueLabels r'
, KnownSymbol name
, r .! name ≈ a
, r' .! name ≈ b
, r' ≈ (r .- name) .\/ (name .== b))
=> AsConstructor name (Var r) (Var r') a b where
_Ctor = focus (Label @name)
{-# INLINE _Ctor #-}
instance {-# OVERLAPPING #-}
( AllUniqueLabels r
, KnownSymbol name
, r .! name ≈ a
, r ≈ (r .- name) .\/ (name .== a))
=> AsConstructor' name (Var r) a where
_Ctor' = focus (Label @name)
{-# INLINE _Ctor' #-}