{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -Wno-deprecations #-} module Data.Barbie.Internal.ProductC ( ProductBC(..) , buniqC , CanDeriveProductBC , GAll , GProductBC(..) , gbdictsDefault ) where import Barbies.Generics.Constraints(GAll, Self, Other, X) import Barbies.Internal.ConstraintsB(ConstraintsB(..), GAllRepB) import Barbies.Internal.Dicts(Dict (..), requiringDict) import Barbies.Internal.FunctorB(FunctorB(bmap)) import Barbies.Internal.Trivial(Unit(..)) import Barbies.Internal.Wrappers(Barbie(..)) import Data.Barbie.Internal.Product(ProductB(..)) import Data.Generics.GenericN import Data.Functor.Product (Product (..)) import Data.Kind(Type) import Data.Proxy(Proxy (..)) class (ConstraintsB b, ProductB b) => ProductBC (b :: (k -> Type) -> Type) where bdicts :: AllB c b => b (Dict c) default bdicts :: (CanDeriveProductBC c b, AllB c b) => b (Dict c) bdicts = gbdictsDefault type CanDeriveProductBC c b = ( GenericN (b (Dict c)) , AllB c b ~ GAll 0 c (GAllRepB b) , GProductBC c (GAllRepB b) (RepN (b (Dict c))) ) {-# DEPRECATED buniqC "Use bpureC instead" #-} buniqC :: forall c f b . (AllB c b, ProductBC b) => (forall a . c a => f a) -> b f buniqC x = bmap (requiringDict @c x) bdicts instance ProductBC b => ProductBC (Barbie b) where bdicts = Barbie bdicts instance ProductBC Unit where bdicts = Unit -- =============================================================== -- Generic derivations -- =============================================================== -- | Default implementation of 'bdicts' based on 'Generic'. gbdictsDefault :: forall b c . ( CanDeriveProductBC c b , AllB c b ) => b (Dict c) gbdictsDefault = toN $ gbdicts @c @(GAllRepB b) {-# INLINE gbdictsDefault #-} class GProductBC c repbx repbd where gbdicts :: GAll 0 c repbx => repbd x -- ---------------------------------- -- Trivial cases -- ---------------------------------- instance GProductBC c repbx repbd => GProductBC c (M1 i k repbx) (M1 i k repbd) where gbdicts = M1 (gbdicts @c @repbx) {-# INLINE gbdicts #-} instance GProductBC c U1 U1 where gbdicts = U1 {-# INLINE gbdicts #-} instance ( GProductBC c lx ld , GProductBC c rx rd ) => GProductBC c (lx :*: rx) (ld :*: rd) where gbdicts = gbdicts @c @lx @ld :*: gbdicts @c @rx @rd {-# INLINE gbdicts #-} -- -------------------------------- -- The interesting cases -- -------------------------------- type P0 = Param 0 instance c a => GProductBC c (Rec (P0 X a_or_pma) (X a)) (Rec (P0 (Dict c) a_or_pma) (Dict c a)) where gbdicts = Rec (K1 Dict) {-# INLINE gbdicts #-} instance ( ProductBC b , AllB c b ) => GProductBC c (Self (b' (P0 X)) (b X)) (Rec (b' (P0 (Dict c))) (b (Dict c))) where gbdicts = Rec $ K1 $ bdicts @_ @b instance ( ProductBC b , AllB c b ) => GProductBC c (Other (b' (P0 X)) (b X)) (Rec (b' (P0 (Dict c))) (b (Dict c))) where gbdicts = Rec $ K1 $ bdicts @_ @b -- -------------------------------- -- Instances for base types -- -------------------------------- instance ProductBC Proxy where bdicts = Proxy {-# INLINE bdicts #-} instance (ProductBC a, ProductBC b) => ProductBC (Product a b) where bdicts = Pair bdicts bdicts {-# INLINE bdicts #-}