module Generics.OneLiner.Internal where
import GHC.Generics
import GHC.Types (Constraint)
import Control.Applicative
import Data.Bifunctor.Biff
import Data.Bifunctor.Clown
import Data.Bifunctor.Joker
import Data.Bifunctor.Product
import Data.Bifunctor.Tannen
import Data.Functor.Contravariant.Divisible
import Data.Functor.Compose
import Data.Functor.Identity
import Data.Profunctor
import Data.Proxy
import Data.Tagged
type family Constraints' (t :: * -> *) (c :: * -> Constraint) (c1 :: (* -> *) -> Constraint) :: Constraint
type instance Constraints' V1 c c1 = ()
type instance Constraints' U1 c c1 = ()
type instance Constraints' (f :+: g) c c1 = (Constraints' f c c1, Constraints' g c c1)
type instance Constraints' (f :*: g) c c1 = (Constraints' f c c1, Constraints' g c c1)
type instance Constraints' (f :.: g) c c1 = (c1 f, Constraints' g c c1)
type instance Constraints' Par1 c c1 = ()
type instance Constraints' (Rec1 f) c c1 = c1 f
type instance Constraints' (K1 i a) c c1 = c a
type instance Constraints' (M1 i t f) c c1 = Constraints' f c c1
type ADT' = ADT_ Identity Proxy ADTProfunctor
type ADTNonEmpty' = ADT_ Identity Proxy NonEmptyProfunctor
type ADTRecord' = ADT_ Identity Proxy RecordProfunctor
type ADT1' t = (ADT_ Identity Identity ADTProfunctor t, ADT_ Proxy Identity ADTProfunctor t)
type ADTNonEmpty1' t = (ADT_ Identity Identity NonEmptyProfunctor t, ADT_ Proxy Identity NonEmptyProfunctor t)
type ADTRecord1' t = (ADT_ Identity Identity RecordProfunctor t, ADT_ Proxy Identity RecordProfunctor t)
type ADTProfunctor = GenericEmptyProfunctor ': NonEmptyProfunctor
type NonEmptyProfunctor = GenericSumProfunctor ': RecordProfunctor
type RecordProfunctor = '[GenericProductProfunctor, GenericUnitProfunctor, Profunctor]
type family Satisfies (p :: * -> * -> *) (ks :: [(* -> * -> *) -> Constraint]) :: Constraint
type instance Satisfies p (k ': ks) = (k p, Satisfies p ks)
type instance Satisfies p '[] = ()
class (ks :: [(* -> * -> *) -> Constraint]) |- (k :: (* -> * -> *) -> Constraint) where
(|-) :: Satisfies p ks => proxy0 ks -> proxy1 k -> (k p => p a b) -> p a b
instance ks |- k => (_k ': ks) |- k where
(_ :: proxy0 (_k ': ks)) |- proxy1 = (Proxy :: Proxy ks) |- proxy1
instance (k ': _ks) |- k where
_ |- _ = id
generic' :: forall t c p ks a b proxy0 for. (ADT_ Identity Proxy ks t, Constraints' t c AnyType, Satisfies p ks)
=> proxy0 ks
-> for c
-> (forall s. c s => p s s)
-> p (t a) (t b)
generic' proxy0 for f = generic_ proxy0 (Proxy :: Proxy Identity) for (Identity f) (Proxy :: Proxy AnyType) Proxy Proxy
generic1' :: forall t c1 p ks a b proxy0 for. (ADT_ Proxy Identity ks t, Constraints' t AnyType c1, Satisfies p ks)
=> proxy0 ks
-> for c1
-> (forall s d e. c1 s => p d e -> p (s d) (s e))
-> p a b
-> p (t a) (t b)
generic1' proxy0 for f p = generic_ proxy0 (Proxy :: Proxy Proxy) (Proxy :: Proxy AnyType) Proxy for (Identity f) (Identity p)
generic01' :: forall t c0 c1 p ks a b proxy0 for for1. (ADT_ Identity Identity ks t, Constraints' t c0 c1, Satisfies p ks)
=> proxy0 ks
-> for c0
-> (forall s. c0 s => p s s)
-> for1 c1
-> (forall s d e. c1 s => p d e -> p (s d) (s e))
-> p a b
-> p (t a) (t b)
generic01' proxy0 for0 k for1 f p = generic_ proxy0 (Proxy :: Proxy Identity) for0 (Identity k) for1 (Identity f) (Identity p)
class ADT_ (nullary :: * -> *) (unary :: * -> *) (ks :: [(* -> * -> *) -> Constraint]) (t :: * -> *) where
generic_ :: (Constraints' t c c1, Satisfies p ks)
=> proxy0 ks
-> proxy1 nullary
-> for c
-> (forall s. c s => nullary (p s s))
-> for1 c1
-> (forall s1 d e. c1 s1 => unary (p d e -> p (s1 d) (s1 e)))
-> unary (p a b)
-> p (t a) (t b)
instance ks |- GenericEmptyProfunctor => ADT_ nullary unary ks V1 where
generic_ proxy0 _ _ _ _ _ _ = (proxy0 |- (Proxy :: Proxy GenericEmptyProfunctor)) zero
instance ks |- GenericUnitProfunctor => ADT_ nullary unary ks U1 where
generic_ proxy0 _ _ _ _ _ _ = (proxy0 |- (Proxy :: Proxy GenericUnitProfunctor)) unit
instance (ks |- GenericSumProfunctor, ADT_ nullary unary ks f, ADT_ nullary unary ks g) => ADT_ nullary unary ks (f :+: g) where
generic_ proxy0 proxy1 for f for1 f1 p1 = (proxy0 |- (Proxy :: Proxy GenericSumProfunctor))
(plus (generic_ proxy0 proxy1 for f for1 f1 p1) (generic_ proxy0 proxy1 for f for1 f1 p1))
instance (ks |- GenericProductProfunctor, ADT_ nullary unary ks f, ADT_ nullary unary ks g) => ADT_ nullary unary ks (f :*: g) where
generic_ proxy0 proxy1 for f for1 f1 p1 = (proxy0 |- (Proxy :: Proxy GenericProductProfunctor))
(mult (generic_ proxy0 proxy1 for f for1 f1 p1) (generic_ proxy0 proxy1 for f for1 f1 p1))
instance ks |- Profunctor => ADT_ Identity unary ks (K1 i v) where
generic_ proxy0 _ _ f _ _ _ = (proxy0 |- (Proxy :: Proxy Profunctor)) (dimap unK1 K1 (runIdentity f))
instance ks |- GenericEmptyProfunctor => ADT_ Proxy unary ks (K1 i v) where
generic_ proxy0 _ _ _ _ _ _ = (proxy0 |- (Proxy :: Proxy GenericEmptyProfunctor)) (dimap unK1 K1 identity)
instance (ks |- Profunctor, ADT_ nullary unary ks f) => ADT_ nullary unary ks (M1 i c f) where
generic_ proxy0 proxy1 for f for1 f1 p1 = (proxy0 |- (Proxy :: Proxy Profunctor))
(dimap unM1 M1 (generic_ proxy0 proxy1 for f for1 f1 p1))
instance (ks |- Profunctor, ADT_ nullary Identity ks g) => ADT_ nullary Identity ks (f :.: g) where
generic_ proxy0 proxy1 for f for1 f1 p1 = (proxy0 |- (Proxy :: Proxy Profunctor))
(dimap unComp1 Comp1 $ runIdentity f1 (generic_ proxy0 proxy1 for f for1 f1 p1))
instance ks |- Profunctor => ADT_ nullary Identity ks Par1 where
generic_ proxy0 _ _ _ _ _ p = (proxy0 |- (Proxy :: Proxy Profunctor))
(dimap unPar1 Par1 (runIdentity p))
instance ks |- Profunctor => ADT_ nullary Identity ks (Rec1 f) where
generic_ proxy0 _ _ _ _ f p = (proxy0 |- (Proxy :: Proxy Profunctor))
(dimap unRec1 Rec1 (runIdentity (f <*> p)))
absurd :: V1 a -> b
absurd = \case {}
e1 :: (f a -> b) -> (g a -> b) -> (f :+: g) a -> b
e1 f _ (L1 l) = f l
e1 _ f (R1 r) = f r
fst1 :: (f :*: g) a -> f a
fst1 (l :*: _) = l
snd1 :: (f :*: g) a -> g a
snd1 (_ :*: r) = r
class Profunctor p => GenericUnitProfunctor p where
unit :: p (U1 a) (U1 a')
class Profunctor p => GenericProductProfunctor p where
mult :: p (f a) (f' a') -> p (g a) (g' a') -> p ((f :*: g) a) ((f' :*: g') a')
class Profunctor p => GenericSumProfunctor p where
plus :: p (f a) (f' a') -> p (g a) (g' a') -> p ((f :+: g) a) ((f' :+: g') a')
class Profunctor p => GenericEmptyProfunctor p where
identity :: p a a
zero :: p (V1 a) (V1 a')
class (Profunctor p, GenericUnitProfunctor p, GenericProductProfunctor p) => GenericRecordProfunctor p
instance (Profunctor p, GenericUnitProfunctor p, GenericProductProfunctor p) => GenericRecordProfunctor p
class (GenericRecordProfunctor p, GenericSumProfunctor p) => GenericNonEmptyProfunctor p where
instance (GenericRecordProfunctor p, GenericSumProfunctor p) => GenericNonEmptyProfunctor p where
class (GenericNonEmptyProfunctor p, GenericEmptyProfunctor p) => GenericProfunctor p where
instance (GenericNonEmptyProfunctor p, GenericEmptyProfunctor p) => GenericProfunctor p where
instance GenericUnitProfunctor (->) where
unit _ = U1
instance GenericProductProfunctor (->) where
mult f g (l :*: r) = f l :*: g r
instance GenericSumProfunctor (->) where
plus f g = e1 (L1 . f) (R1 . g)
instance GenericEmptyProfunctor (->) where
zero = absurd
identity = id
instance GenericUnitProfunctor Tagged where
unit = Tagged U1
instance GenericProductProfunctor Tagged where
mult (Tagged l) (Tagged r) = Tagged $ l :*: r
instance Applicative f => GenericUnitProfunctor (Star f) where
unit = Star $ \_ -> pure U1
instance Applicative f => GenericProductProfunctor (Star f) where
mult (Star f) (Star g) = Star $ \(l :*: r) -> (:*:) <$> f l <*> g r
instance Applicative f => GenericSumProfunctor (Star f) where
plus (Star f) (Star g) = Star $ e1 (fmap L1 . f) (fmap R1 . g)
instance Applicative f => GenericEmptyProfunctor (Star f) where
zero = Star absurd
identity = Star pure
instance Functor f => GenericUnitProfunctor (Costar f) where
unit = Costar $ const U1
instance Functor f => GenericProductProfunctor (Costar f) where
mult (Costar f) (Costar g) = Costar $ \lr -> f (fst1 <$> lr) :*: g (snd1 <$> lr)
instance (Functor f, Applicative g, Profunctor p, GenericUnitProfunctor p) => GenericUnitProfunctor (Biff p f g) where
unit = Biff $ dimap (const U1) pure unit
instance (Functor f, Applicative g, Profunctor p, GenericProductProfunctor p) => GenericProductProfunctor (Biff p f g) where
mult (Biff f) (Biff g) = Biff $ dimap
(liftA2 (:*:) (Compose . fmap fst1) (Compose . fmap snd1))
(\(Compose l :*: Compose r) -> liftA2 (:*:) l r)
(mult (dimap getCompose Compose f) (dimap getCompose Compose g))
instance Applicative f => GenericUnitProfunctor (Joker f) where
unit = Joker $ pure U1
instance Applicative f => GenericProductProfunctor (Joker f) where
mult (Joker l) (Joker r) = Joker $ (:*:) <$> l <*> r
instance Alternative f => GenericSumProfunctor (Joker f) where
plus (Joker l) (Joker r) = Joker $ L1 <$> l <|> R1 <$> r
instance Alternative f => GenericEmptyProfunctor (Joker f) where
zero = Joker empty
identity = Joker empty
instance Divisible f => GenericUnitProfunctor (Clown f) where
unit = Clown conquer
instance Divisible f => GenericProductProfunctor (Clown f) where
mult (Clown f) (Clown g) = Clown $ divide (\(l :*: r) -> (l, r)) f g
instance Decidable f => GenericSumProfunctor (Clown f) where
plus (Clown f) (Clown g) = Clown $ choose (e1 Left Right) f g
instance Decidable f => GenericEmptyProfunctor (Clown f) where
zero = Clown $ lose absurd
identity = Clown conquer
instance (GenericUnitProfunctor p, GenericUnitProfunctor q) => GenericUnitProfunctor (Product p q) where
unit = Pair unit unit
instance (GenericProductProfunctor p, GenericProductProfunctor q) => GenericProductProfunctor (Product p q) where
mult (Pair l1 r1) (Pair l2 r2) = Pair (mult l1 l2) (mult r1 r2)
instance (GenericSumProfunctor p, GenericSumProfunctor q) => GenericSumProfunctor (Product p q) where
plus (Pair l1 r1) (Pair l2 r2) = Pair (plus l1 l2) (plus r1 r2)
instance (GenericEmptyProfunctor p, GenericEmptyProfunctor q) => GenericEmptyProfunctor (Product p q) where
zero = Pair zero zero
identity = Pair identity identity
instance (Applicative f, GenericUnitProfunctor p) => GenericUnitProfunctor (Tannen f p) where
unit = Tannen (pure unit)
instance (Applicative f, GenericProductProfunctor p) => GenericProductProfunctor (Tannen f p) where
mult (Tannen l) (Tannen r) = Tannen $ liftA2 mult l r
instance (Applicative f, GenericSumProfunctor p) => GenericSumProfunctor (Tannen f p) where
plus (Tannen l) (Tannen r) = Tannen $ liftA2 plus l r
instance (Applicative f, GenericEmptyProfunctor p) => GenericEmptyProfunctor (Tannen f p) where
zero = Tannen (pure zero)
identity = Tannen (pure identity)
data Ctor a b = Ctor { index :: a -> Int, count :: Int }
instance Profunctor Ctor where
dimap l _ (Ctor i c) = Ctor (i . l) c
instance GenericUnitProfunctor Ctor where
unit = Ctor (const 0) 1
instance GenericProductProfunctor Ctor where
mult _ _ = Ctor (const 0) 1
instance GenericSumProfunctor Ctor where
plus l r = Ctor (e1 (index l) ((count l + ) . index r)) (count l + count r)
instance GenericEmptyProfunctor Ctor where
zero = Ctor (const 0) 0
identity = Ctor (const 0) 1
record :: forall c p t. (ADTRecord t, Constraints t c, GenericRecordProfunctor p)
=> (forall s. c s => p s s) -> p t t
record f = dimap from to $ generic' (Proxy :: Proxy RecordProfunctor) (Proxy :: Proxy c) f
record1 :: forall c p t a b. (ADTRecord1 t, Constraints1 t c, GenericRecordProfunctor p)
=> (forall d e s. c s => p d e -> p (s d) (s e)) -> p a b -> p (t a) (t b)
record1 f p = dimap from1 to1 $ generic1' (Proxy :: Proxy RecordProfunctor) (Proxy :: Proxy c) f p
record01 :: forall c0 c1 p t a b. (ADTRecord1 t, Constraints01 t c0 c1, GenericRecordProfunctor p)
=> (forall s. c0 s => p s s) -> (forall d e s. c1 s => p d e -> p (s d) (s e)) -> p a b -> p (t a) (t b)
record01 k f p = dimap from1 to1 $ generic01' (Proxy :: Proxy RecordProfunctor) (Proxy :: Proxy c0) k (Proxy :: Proxy c1) f p
nonEmpty :: forall c p t. (ADTNonEmpty t, Constraints t c, GenericNonEmptyProfunctor p)
=> (forall s. c s => p s s) -> p t t
nonEmpty f = dimap from to $ generic' (Proxy :: Proxy NonEmptyProfunctor) (Proxy :: Proxy c) f
nonEmpty1 :: forall c p t a b. (ADTNonEmpty1 t, Constraints1 t c, GenericNonEmptyProfunctor p)
=> (forall d e s. c s => p d e -> p (s d) (s e)) -> p a b -> p (t a) (t b)
nonEmpty1 f p = dimap from1 to1 $ generic1' (Proxy :: Proxy NonEmptyProfunctor) (Proxy :: Proxy c) f p
nonEmpty01 :: forall c0 c1 p t a b. (ADTNonEmpty1 t, Constraints01 t c0 c1, GenericNonEmptyProfunctor p)
=> (forall s. c0 s => p s s) -> (forall d e s. c1 s => p d e -> p (s d) (s e)) -> p a b -> p (t a) (t b)
nonEmpty01 k f p = dimap from1 to1 $ generic01' (Proxy :: Proxy NonEmptyProfunctor) (Proxy :: Proxy c0) k (Proxy :: Proxy c1) f p
generic :: forall c p t. (ADT t, Constraints t c, GenericProfunctor p)
=> (forall s. c s => p s s) -> p t t
generic f = dimap from to $ generic' (Proxy :: Proxy ADTProfunctor) (Proxy :: Proxy c) f
generic1 :: forall c p t a b. (ADT1 t, Constraints1 t c, GenericProfunctor p)
=> (forall d e s. c s => p d e -> p (s d) (s e)) -> p a b -> p (t a) (t b)
generic1 f p = dimap from1 to1 $ generic1' (Proxy :: Proxy ADTProfunctor) (Proxy :: Proxy c) f p
generic01 :: forall c0 c1 p t a b. (ADT1 t, Constraints01 t c0 c1, GenericProfunctor p)
=> (forall s. c0 s => p s s) -> (forall d e s. c1 s => p d e -> p (s d) (s e)) -> p a b -> p (t a) (t b)
generic01 k f p = dimap from1 to1 $ generic01' (Proxy :: Proxy ADTProfunctor) (Proxy :: Proxy c0) k (Proxy :: Proxy c1) f p
type Constraints t c = Constraints' (Rep t) c AnyType
type Constraints1 t c = Constraints' (Rep1 t) AnyType c
type Constraints01 t c0 c1 = Constraints' (Rep1 t) c0 c1
type ADTRecord t = (Generic t, ADTRecord' (Rep t), Constraints t AnyType)
type ADTRecord1 t = (Generic1 t, ADTRecord1' (Rep1 t), Constraints1 t AnyType)
type ADTNonEmpty t = (Generic t, ADTNonEmpty' (Rep t), Constraints t AnyType)
type ADTNonEmpty1 t = (Generic1 t, ADTNonEmpty1' (Rep1 t), Constraints1 t AnyType)
type ADT t = (Generic t, ADT' (Rep t), Constraints t AnyType)
type ADT1 t = (Generic1 t, ADT1' (Rep1 t), Constraints1 t AnyType)
ctorIndex :: ADT t => t -> Int
ctorIndex = index $ generic @AnyType (Ctor (const 0) 1)
ctorIndex1 :: ADT1 t => t a -> Int
ctorIndex1 = index $ generic1 @AnyType (const $ Ctor (const 0) 1) (Ctor (const 0) 1)
class AnyType (a :: k)
instance AnyType (a :: k)
type family FunResult t where
FunResult (a -> b) = FunResult b
FunResult r = r
class FunConstraints c t where
autoApply :: Applicative f => (forall s. c s => f s) -> f t -> f (FunResult t)
instance (c a, FunConstraints c b) => FunConstraints c (a -> b) where
autoApply run f = autoApply @c run (f <*> run)
instance FunResult r ~ r => FunConstraints c r where
autoApply _run r = r