{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
module Agda.Utils.TypeLevel where
import Data.Proxy
import GHC.Exts (Constraint)
type family All (p :: k -> Constraint) (as :: [k]) :: Constraint where
All p '[] = ()
All p (a ': as) = (p a, All p as)
type family If (b :: Bool) (l :: k) (r :: k) :: k where
If 'True l r = l
If 'False l r = r
type family Foldr (c :: k -> l -> l) (n :: l) (as :: [k]) :: l where
Foldr c n '[] = n
Foldr c n (a ': as) = c a (Foldr c n as)
type family Foldr' (c :: Function k (Function l l -> *) -> *)
(n :: l) (as :: [k]) :: l where
Foldr' c n '[] = n
Foldr' c n (a ': as) = Apply (Apply c a) (Foldr' c n as)
type family Map (f :: Function k l -> *) (as :: [k]) :: [l] where
Map f as = Foldr' (ConsMap0 f) '[] as
data ConsMap0 :: (Function k l -> *) -> Function k (Function [l] [l] -> *) -> *
data ConsMap1 :: (Function k l -> *) -> k -> Function [l] [l] -> *
type instance Apply (ConsMap0 f) a = ConsMap1 f a
type instance Apply (ConsMap1 f a) tl = Apply f a ': tl
type family Constant (b :: l) (as :: [k]) :: [l] where
Constant b as = Map (Constant1 b) as
type Arrows (as :: [*]) (r :: *) = Foldr (->) r as
type Products (as :: [*]) = Foldr (,) () as
type family IsBase (t :: *) :: Bool where
IsBase (a -> t) = 'False
IsBase a = 'True
type family Domains (t :: *) :: [*] where
Domains t = If (IsBase t) '[] (Domains' t)
type family Domains' (t :: *) :: [*] where
Domains' (a -> t) = a ': Domains t
type family CoDomain (t :: *) :: * where
CoDomain t = If (IsBase t) t (CoDomain' t)
type family CoDomain' (t :: *) :: * where
CoDomain' (a -> t) = CoDomain t
class Currying as b where
uncurrys :: Proxy as -> Proxy b -> Arrows as b -> Products as -> b
currys :: Proxy as -> Proxy b -> (Products as -> b) -> Arrows as b
instance Currying '[] b where
uncurrys _ _ f = \ () -> f
currys _ _ f = f ()
instance Currying as b => Currying (a ': as) b where
uncurrys _ p f = uncurry $ uncurrys (Proxy :: Proxy as) p . f
currys _ p f = currys (Proxy :: Proxy as) p . curry f
data Function :: * -> * -> *
data Constant0 :: Function a (Function b a -> *) -> *
data Constant1 :: * -> Function b a -> *
type family Apply (t :: Function k l -> *) (u :: k) :: l
type instance Apply Constant0 a = Constant1 a
type instance Apply (Constant1 a) b = a