module Generics.OneLiner.Classes where
import GHC.Generics
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.Profunctor
import Data.Tagged
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
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')
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)
newtype Zip f a b = Zip { runZip :: a -> a -> f b }
instance Functor f => Profunctor (Zip f) where
dimap f g (Zip h) = Zip $ \a1 a2 -> fmap g (h (f a1) (f a2))
instance Applicative f => GenericUnitProfunctor (Zip f) where
unit = Zip $ \_ _ -> pure U1
instance Applicative f => GenericProductProfunctor (Zip f) where
mult (Zip f) (Zip g) = Zip $ \(al :*: ar) (bl :*: br) -> (:*:) <$> f al bl <*> g ar br
instance Alternative f => GenericSumProfunctor (Zip f) where
plus (Zip f) (Zip g) = Zip h where
h (L1 a) (L1 b) = fmap L1 (f a b)
h (R1 a) (R1 b) = fmap R1 (g a b)
h _ _ = empty
instance Alternative f => GenericEmptyProfunctor (Zip f) where
zero = Zip absurd
identity = Zip $ \_ _ -> empty
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