{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Barbies.Internal.ConstraintsB
( ConstraintsB(..)
, bmapC
, btraverseC
, AllBF
, bdicts
, bpureC
, bmempty
, bzipWithC
, bzipWith3C
, bzipWith4C
, bfoldMapC
, CanDeriveConstraintsB
, gbaddDictsDefault
, GAllRepB
)
where
import Barbies.Generics.Constraints(GConstraints(..), GAll, TagSelf, Self, Other, X)
import Barbies.Internal.ApplicativeB(ApplicativeB(..))
import Barbies.Internal.Dicts(ClassF, Dict (..), requiringDict)
import Barbies.Internal.FunctorB(FunctorB (..))
import Barbies.Internal.TraversableB(TraversableB (..))
import Data.Functor.Compose (Compose (..))
import Data.Functor.Const (Const (..))
import Data.Functor.Product (Product (..))
import Data.Functor.Sum (Sum (..))
import Data.Kind (Constraint)
import Data.Proxy (Proxy (..))
import Data.Generics.GenericN
class FunctorB b => ConstraintsB (b :: (k -> *) -> *) where
type AllB (c :: k -> Constraint) b :: Constraint
type AllB c b = GAll 0 c (GAllRepB b)
baddDicts
:: forall c f
. AllB c b
=> b f
-> b (Dict c `Product` f)
default baddDicts
:: forall c f
. ( CanDeriveConstraintsB c b f
, AllB c b
)
=> b f -> b (Dict c `Product` f)
baddDicts = gbaddDictsDefault
bmapC :: forall c b f g
. (AllB c b, ConstraintsB b)
=> (forall a. c a => f a -> g a)
-> b f
-> b g
bmapC f bf
= bmap go (baddDicts bf)
where
go :: forall a. (Dict c `Product` f) a -> g a
go (d `Pair` fa) = requiringDict (f fa) d
btraverseC
:: forall c b f g e
. (TraversableB b, ConstraintsB b, AllB c b, Applicative e)
=> (forall a. c a => f a -> e (g a))
-> b f
-> e (b g)
btraverseC f b
= btraverse (\(Pair (Dict :: Dict c a) x) -> f x) (baddDicts b)
bfoldMapC
:: forall c b m f
. (TraversableB b, ConstraintsB b, AllB c b, Monoid m)
=> (forall a. c a => f a -> m)
-> b f
-> m
bfoldMapC f = getConst . btraverseC @c (Const . f)
bzipWithC
:: forall c b f g h
. (AllB c b, ConstraintsB b, ApplicativeB b)
=> (forall a. c a => f a -> g a -> h a)
-> b f
-> b g
-> b h
bzipWithC f bf bg
= bmapC @c go (bf `bprod` bg)
where
go :: forall a. c a => Product f g a -> h a
go (Pair fa ga) = f fa ga
bzipWith3C
:: forall c b f g h i
. (AllB c b, ConstraintsB b, ApplicativeB b)
=> (forall a. c a => f a -> g a -> h a -> i a)
-> b f -> b g -> b h -> b i
bzipWith3C f bf bg bh
= bmapC @c go (bf `bprod` bg `bprod` bh)
where
go :: forall a. c a => Product (Product f g) h a -> i a
go (Pair (Pair fa ga) ha) = f fa ga ha
bzipWith4C
:: forall c b f g h i j
. (AllB c b, ConstraintsB b, ApplicativeB b)
=> (forall a. c a => f a -> g a -> h a -> i a -> j a)
-> b f -> b g -> b h -> b i -> b j
bzipWith4C f bf bg bh bi
= bmapC @c go (bf `bprod` bg `bprod` bh `bprod` bi)
where
go :: forall a. c a => Product (Product (Product f g) h) i a -> j a
go (Pair (Pair (Pair fa ga) ha) ia) = f fa ga ha ia
type AllBF c f b = AllB (ClassF c f) b
bdicts
:: forall c b
. (ConstraintsB b, ApplicativeB b, AllB c b)
=> b (Dict c)
bdicts
= bmap (\(Pair c _) -> c) $ baddDicts $ bpure Proxy
bpureC
:: forall c f b
. ( AllB c b
, ConstraintsB b
, ApplicativeB b
)
=> (forall a . c a => f a)
-> b f
bpureC fa
= bmap (requiringDict @c fa) bdicts
bmempty
:: forall f b
. ( AllBF Monoid f b
, ConstraintsB b
, ApplicativeB b
)
=> b f
bmempty
= bpureC @(ClassF Monoid f) mempty
type CanDeriveConstraintsB c b f
= ( GenericP 0 (b f)
, GenericP 0 (b (Dict c `Product` f))
, AllB c b ~ GAll 0 c (GAllRepB b)
, GConstraints 0 c f (GAllRepB b) (RepP 0 (b f)) (RepP 0 (b (Dict c `Product` f)))
)
type GAllRepB b = TagSelf 0 b (RepN (b X))
gbaddDictsDefault
:: forall b c f
. ( CanDeriveConstraintsB c b f
, AllB c b
)
=> b f
-> b (Dict c `Product` f)
gbaddDictsDefault
= toP (Proxy @0) . gaddDicts @0 @c @f @(GAllRepB b) . fromP (Proxy @0)
{-# INLINE gbaddDictsDefault #-}
type P = Param
instance
( ConstraintsB b
, AllB c b
) =>
GConstraints 0 c f (Rec (Self b' (P 0 X)) (b X))
(Rec (b (P 0 f)) (b f))
(Rec (b (P 0 (Dict c `Product` f)))
(b (Dict c `Product` f)))
where
gaddDicts
= Rec . K1 . baddDicts . unK1 . unRec
{-# INLINE gaddDicts #-}
type instance GAll 0 c (Rec (Other b (P 0 X)) (b' X)) = AllB c b'
instance
( ConstraintsB b
, AllB c b
) => GConstraints 0 c f (Rec (Other b' (P 0 X)) (b X))
(Rec (b (P 0 f)) (b f))
(Rec (b (P 0 (Dict c `Product` f)))
(b (Dict c `Product` f)))
where
gaddDicts
= Rec . K1 . baddDicts . unK1 . unRec
{-# INLINE gaddDicts #-}
instance ConstraintsB Proxy where
type AllB c Proxy = ()
baddDicts _ = Proxy
{-# INLINE baddDicts #-}
instance (ConstraintsB a, ConstraintsB b) => ConstraintsB (Product a b) where
type AllB c (Product a b) = (AllB c a, AllB c b)
baddDicts (Pair x y) = Pair (baddDicts x) (baddDicts y)
{-# INLINE baddDicts #-}
instance (ConstraintsB a, ConstraintsB b) => ConstraintsB (Sum a b) where
type AllB c (Sum a b) = (AllB c a, AllB c b)
baddDicts (InL x) = InL (baddDicts x)
baddDicts (InR x) = InR (baddDicts x)
{-# INLINE baddDicts #-}
instance ConstraintsB (Const a) where
type AllB c (Const a) = ()
baddDicts (Const x) = Const x
{-# INLINE baddDicts #-}
instance (Functor f, ConstraintsB b) => ConstraintsB (f `Compose` b) where
type AllB c (f `Compose` b) = AllB c b
baddDicts (Compose x)
= Compose (baddDicts <$> x)
{-# INLINE baddDicts #-}