{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}
module Barbies.Generics.Constraints
( GAll
, X, Y
, TagSelf, TagSelf', Self, Other
, GConstraints(..)
)
where
import Barbies.Internal.Dicts(Dict (..))
import Data.Functor.Product (Product (..))
import Data.Kind (Constraint, Type)
import GHC.TypeLits (Nat, type (+))
import Data.Generics.GenericN
class GConstraints n c f repbx repbf repbdf where
gaddDicts :: GAll n c repbx => repbf x -> repbdf x
type family GAll (n :: Nat) (c :: k -> Constraint) (repbf :: Type -> Type) :: Constraint
data X a
data family Y :: k
type instance GAll n c (M1 i k repbf) = GAll n c repbf
instance
GConstraints n c f repbx repbf repbdf
=> GConstraints n c f (M1 i k repbx)
(M1 i k repbf)
(M1 i k repbdf)
where
gaddDicts
= M1 . gaddDicts @n @c @f @repbx . unM1
{-# INLINE gaddDicts #-}
type instance GAll n c V1 = ()
instance GConstraints n c f V1 V1 V1 where
gaddDicts _ = undefined
type instance GAll n c U1 = ()
instance GConstraints n c f U1 U1 U1 where
gaddDicts = id
{-# INLINE gaddDicts #-}
type instance GAll n c (l :*: r)
= (GAll n c l, GAll n c r)
instance
( GConstraints n c f lx lf ldf
, GConstraints n c f rx rf rdf
) => GConstraints n c f (lx :*: rx)
(lf :*: rf)
(ldf :*: rdf)
where
gaddDicts (l :*: r)
= (gaddDicts @n @c @f @lx l) :*: (gaddDicts @n @c @f @rx r)
{-# INLINE gaddDicts #-}
type instance GAll n c (l :+: r) = (GAll n c l, GAll n c r)
instance
( GConstraints n c f lx lf ldf
, GConstraints n c f rx rf rdf
) => GConstraints n c f (lx :+: rx)
(lf :+: rf)
(ldf :+: rdf)
where
gaddDicts = \case
L1 l -> L1 (gaddDicts @n @c @f @lx l)
R1 r -> R1 (gaddDicts @n @c @f @rx r)
{-# INLINE gaddDicts #-}
type P = Param
type instance GAll n c (Rec (P n X _) (X a)) = c a
instance
GConstraints n c f (Rec (P n X a') (X a))
(Rec (P n f a) (f a))
(Rec (P n (Dict c `Product` f) a)
((Dict c `Product` f) a))
where
gaddDicts
= Rec . K1 . Pair Dict . unK1 . unRec
{-# INLINE gaddDicts #-}
type instance GAll 0 c (Rec (Self b' (P 0 X)) (b X)) = ()
type instance GAll 1 c (Rec (Self b' (P 1 X) (P 0 Y)) (b X Y)) = ()
type instance GAll n c (Rec a a) = ()
instance
GConstraints n c f (Rec a' a)
(Rec a a)
(Rec a a)
where
gaddDicts = id
{-# INLINE gaddDicts #-}
data family Self (b :: k -> k') :: k -> k'
data family Other (b :: k -> k') :: k -> k'
type TagSelf n b repbf
= TagSelf' n b (Indexed b (n + 1)) repbf
type family TagSelf' (n :: Nat) (b :: kb) (b' :: kb) (repbf :: * -> *) :: * -> * where
TagSelf' n b b' (M1 mt m s)
= M1 mt m (TagSelf' n b b' s)
TagSelf' n b b' (l :+: r)
= TagSelf' n b b' l :+: TagSelf' n b b' r
TagSelf' n b b' (l :*: r)
= TagSelf' n b b' l :*: TagSelf' n b b' r
TagSelf' 0 b b' (Rec (b' f) (b g))
= Rec (Self b' f) (b g)
TagSelf' 0 (b :: k -> *) b' (Rec ((b'' :: k -> *) f) ((b''' :: k -> *) g))
= Rec (Other b'' f) (b''' g)
TagSelf' 1 b b' (Rec (b' fl fr) (b gl gr))
= Rec (Self b' fl fr) (b gl gr)
TagSelf' 1 (b :: kl -> kr -> *) b' (Rec ((b'' :: kl -> kr -> *) fl fr) ((b''' :: kl -> kr -> *) gl gr))
= Rec (Other b'' fl fr) (b''' gl gr)
TagSelf' n b b' (Rec p a)
= Rec p a
TagSelf' n b b' U1
= U1
TagSelf' n b b' V1
= V1