{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PatternSynonyms #-}
module Generics.Simplistic.Util
(
(&&&) , (***) , (:->) , (<.>)
, (:*:)(..) , Delta , curry' , uncurry' , delta , deltaMap
, Sum(..) , either' , either''
, Implies , Trivial
, EqHO(..) , ShowHO(..)
, Exists(..) , exMap , exMapM , exElim
, Elem , NotElem , HasElem(..) , ElemPrf(..) , IsElem, sameTy
, All , Witness(..) , witness , witnessPrf
, weq , wshow
) where
import Data.Kind (Constraint)
import Data.Proxy (Proxy(..))
import Data.Functor.Sum
import Data.Functor.Const
import Data.Type.Equality
import Control.Arrow ((***) , (&&&))
import GHC.Generics ((:*:)(..), V1 , U1(..))
curry' :: ((f :*: g) x -> a) -> f x -> g x -> a
curry' f fx gx = f (fx :*: gx)
uncurry' :: (f x -> g x -> a) -> (f :*: g) x -> a
uncurry' f (fx :*: gx) = f fx gx
type f :-> g = forall n . f n -> g n
type Delta f = f :*: f
delta :: f :-> Delta f
delta fx = fx :*: fx
deltaMap :: (f :-> g) -> Delta f :-> Delta g
deltaMap f (x :*: y) = f x :*: f y
either' :: (f :-> r) -> (g :-> r) -> Sum f g :-> r
either' f _ (InL x) = f x
either' _ g (InR x) = g x
either'' :: (forall x . f x -> a) -> (forall y . g y -> a) -> Sum f g r -> a
either'' f g = getConst . either' (Const . f) (Const . g)
infixr 8 <.>
(<.>) :: (Monad m) => (b -> m c) -> (a -> m b) -> a -> m c
f <.> g = (>>= f) . g
class (c => d) => Implies c d
instance (c => d) => Implies c d
class Trivial c
instance Trivial c
class EqHO (f :: ki -> *) where
eqHO :: forall k . f k -> f k -> Bool
instance Eq a => EqHO (Const a) where
eqHO (Const a) (Const b) = a == b
instance (EqHO f, EqHO g) => EqHO (f :*: g) where
eqHO (fx :*: gx) (fy :*: gy) = eqHO fx fy && eqHO gx gy
instance (EqHO f, EqHO g) => EqHO (Sum f g) where
eqHO (InL fx) (InL fy) = eqHO fx fy
eqHO (InR gx) (InR gy) = eqHO gx gy
eqHO _ _ = False
instance EqHO V1 where
eqHO _ _ = True
instance EqHO U1 where
eqHO _ _ = True
class ShowHO (f :: ki -> *) where
showHO :: forall k . f k -> String
showsPrecHO :: forall k . Int -> f k -> ShowS
{-# MINIMAL showHO | showsPrecHO #-}
showHO fx = showsPrecHO 0 fx ""
showsPrecHO _ fx s = showHO fx ++ s
instance Show a => ShowHO (Const a) where
showsPrecHO d (Const a) = showParen (d > app_prec) $
showString "Const " . showsPrec (app_prec + 1) a
where app_prec = 10
instance (ShowHO f , ShowHO g) => ShowHO (f :*: g) where
showsPrecHO d (x :*: y) = showParen (d > app_prec) $
showsPrecHO (app_prec+1) x
. showString " :*: "
. showsPrecHO (app_prec+1) y
where app_prec = 10
instance (ShowHO f , ShowHO g) => ShowHO (Sum f g) where
showsPrecHO d (InL fx) = showParen (d > app_prec) $
showString "InL " . showsPrecHO (app_prec + 1) fx
where app_prec = 10
showsPrecHO d (InR gx) = showParen (d > app_prec) $
showString "InR " . showsPrecHO (app_prec + 1) gx
where app_prec = 10
data Exists (f :: k -> *) :: * where
Exists :: f x -> Exists f
exMap :: (forall x . f x -> g x) -> Exists f -> Exists g
exMap f (Exists x) = Exists (f x)
exMapM :: (Monad m) => (forall x . f x -> m (g x)) -> Exists f -> m (Exists g)
exMapM f (Exists x) = Exists <$> f x
exElim :: (forall x . f x -> a) -> Exists f -> a
exElim f (Exists x) = f x
instance ShowHO f => Show (Exists f) where
show = exElim showHO
type family IsElem (a :: k) (as :: [ k ]) :: Bool where
IsElem a (a ': as) = 'True
IsElem a (b ': as) = IsElem a as
IsElem a '[] = 'False
data ElemPrf a as where
Here :: ElemPrf a (a ': as)
There :: ElemPrf a as -> ElemPrf a (b ': as)
class HasElem a as where
hasElem :: ElemPrf a as
instance {-# OVERLAPPING #-} HasElem a (a ': as) where
hasElem = Here
instance {-# OVERLAPPABLE #-}
(HasElem a as) => HasElem a (b ': as) where
hasElem = There hasElem
type Elem a as = (IsElem a as ~ 'True , HasElem a as)
type NotElem a as = IsElem a as ~ 'False
sameTy :: forall fam x y . (Elem x fam , Elem y fam)
=> Proxy fam -> Proxy x -> Proxy y -> Maybe (x :~: y)
sameTy _ _ _ = go (hasElem :: ElemPrf x fam) (hasElem :: ElemPrf y fam)
where
go :: ElemPrf x fam' -> ElemPrf b fam' -> Maybe (x :~: b)
go Here Here = Just Refl
go (There rr) (There y) = go rr y
go _ _ = Nothing
type family All (c :: k -> Constraint) (xs :: [k]) :: Constraint where
All c '[] = ()
All c (x ': xs) = (c x , All c xs)
data Witness c x where
Witness :: (c x) => Witness c x
witness :: forall x xs c
. (HasElem x xs , All c xs)
=> Proxy xs -> Witness c x
witness _ = witnessPrf (hasElem :: ElemPrf x xs)
weq :: forall x xs
. (All Eq xs , Elem x xs)
=> Proxy xs -> x -> x -> Bool
weq p = case witness p :: Witness Eq x of
Witness -> (==)
wshow :: forall x xs
. (All Show xs , Elem x xs)
=> Proxy xs -> x -> String
wshow p = case witness p :: Witness Show x of
Witness -> show
witnessPrf :: (All c xs) => ElemPrf x xs -> Witness c x
witnessPrf Here = Witness
witnessPrf (There p) = witnessPrf p