{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PatternSynonyms #-}
module Generics.MRSOP.Util
(
(&&&) , (***)
, (:->) , (<.>)
, Product(..), (:*:), pattern (:*:) , Delta , curry' , uncurry' , delta
, Sum(..) , either' , either''
, Nat(..) , proxyUnsuc
, SNat(..) , snat2int
, IsNat(..) , getNat , getSNat'
, ListPrf(..) , IsList(..)
, L1 , L2 , L3 , L4
, (:++:) , appendIsListLemma
, Lkup , Idx , El(..) , getElSNat , into
, EqHO(..) , ShowHO(..)
) where
import Data.Proxy
import Data.Type.Equality
import Data.Functor.Product
import Data.Functor.Sum
import Data.Functor.Const
import GHC.TypeLits (TypeError , ErrorMessage(..))
import Control.Arrow ((***) , (&&&))
type (:*:) = Product
pattern (:*:) :: f a -> g a -> Product f g a
pattern (:*:) x y = Pair x y
curry' :: (Product f g x -> a) -> f x -> g x -> a
curry' f fx gx = f (Pair fx gx)
uncurry' :: (f x -> g x -> a) -> Product f g x -> a
uncurry' f (Pair fx gx) = f fx gx
type f :-> g = forall n . f n -> g n
type Delta f = Product f f
delta :: f :-> Delta f
delta fx = Pair fx fx
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
data Nat = S Nat | Z
deriving (Eq , Show)
proxyUnsuc :: Proxy ('S n) -> Proxy n
proxyUnsuc _ = Proxy
data SNat :: Nat -> * where
SZ :: SNat 'Z
SS :: SNat n -> SNat ('S n)
snat2int :: SNat n -> Integer
snat2int SZ = 0
snat2int (SS n) = 1 + snat2int n
class IsNat (n :: Nat) where
getSNat :: Proxy n -> SNat n
instance IsNat 'Z where
getSNat _ = SZ
instance IsNat n => IsNat ('S n) where
getSNat p = SS (getSNat $ proxyUnsuc p)
getNat :: (IsNat n) => Proxy n -> Integer
getNat = snat2int . getSNat
getSNat' :: forall (n :: Nat). IsNat n => SNat n
getSNat' = getSNat (Proxy :: Proxy n)
instance TestEquality SNat where
testEquality SZ SZ = Just Refl
testEquality (SS n) (SS m)
= case testEquality n m of
Nothing -> Nothing
Just Refl -> Just Refl
testEquality _ _ = Nothing
type family Lkup (n :: Nat) (ks :: [k]) :: k where
Lkup 'Z (k : ks) = k
Lkup ('S n) (k : ks) = Lkup n ks
Lkup _ '[] = TypeError ('Text "Lkup index too big")
type family Idx (ty :: k) (xs :: [k]) :: Nat where
Idx x (x ': ys) = 'Z
Idx x (y ': ys) = 'S (Idx x ys)
Idx x '[] = TypeError ('Text "Element not found")
data El :: [*] -> Nat -> * where
El :: IsNat ix => {unEl :: Lkup ix fam} -> El fam ix
getElSNat :: forall ix ls. El ls ix -> SNat ix
getElSNat (El _) = getSNat' @ix
into :: forall fam ty ix
. (ix ~ Idx ty fam , Lkup ix fam ~ ty , IsNat ix)
=> ty -> El fam ix
into = El
data ListPrf :: [k] -> * where
Nil :: ListPrf '[]
Cons :: ListPrf l -> ListPrf (x ': l)
class IsList (xs :: [k]) where
listPrf :: ListPrf xs
instance IsList '[] where
listPrf = Nil
instance IsList xs => IsList (x ': xs) where
listPrf = Cons listPrf
appendIsListLemma :: ListPrf xs -> ListPrf ys -> ListPrf (xs :++: ys)
appendIsListLemma Nil isys = isys
appendIsListLemma (Cons isxs) isys = Cons (appendIsListLemma isxs isys)
type family (:++:) (txs :: [k]) (tys :: [k]) :: [k] where
(:++:) '[] tys = tys
(:++:) (tx ': txs) tys = tx ': (txs :++: tys)
type L1 xs = (IsList xs)
type L2 xs ys = (IsList xs, IsList ys)
type L3 xs ys zs = (IsList xs, IsList ys, IsList zs)
type L4 xs ys zs as = (IsList xs, IsList ys, IsList zs, IsList as)
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 (Product f g) where
eqHO (Pair fx gx) (Pair 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
class ShowHO (f :: ki -> *) where
showHO :: forall k . f k -> String
instance Show a => ShowHO (Const a) where
showHO (Const a) = show a
instance (ShowHO f , ShowHO g) => ShowHO (Product f g) where
showHO (Pair x y) = "(" ++ showHO x ++ ", " ++ showHO y ++ ")"
instance (ShowHO f , ShowHO g) => ShowHO (Sum f g) where
showHO (InL fx) = "InL " ++ showHO fx
showHO (InR gx) = "InR " ++ showHO gx