{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Effect.OpenUnion.Internal where
import Data.Proxy (Proxy (Proxy))
import Data.Type.Equality (type (==))
import GHC.TypeError (ErrorMessage (ShowType, Text, (:$$:), (:<>:)), TypeError)
import GHC.TypeNats (KnownNat, natVal, type (+), type (-))
newtype P (e :: k) (es :: [k]) = P {forall k (e :: k) (es :: [k]). P e es -> Word
unP :: Word}
type FindElem e es = KnownNat (ElemIndex e es)
elemNo :: forall e es. (FindElem e es) => P e es
elemNo :: forall {k} (e :: k) (es :: [k]). FindElem e es => P e es
elemNo = Word -> P e es
forall k (e :: k) (es :: [k]). Word -> P e es
P (Word -> P e es) -> Word -> P e es
forall a b. (a -> b) -> a -> b
$ forall (n :: Nat). KnownNat n => Word
wordVal @(ElemIndex e es)
{-# INLINE elemNo #-}
type family ElemIndex e es where
ElemIndex e (e ': es) = 0
ElemIndex e (_ ': es) = 1 + ElemIndex e es
type family ElemAt i es where
ElemAt 0 (e ': _) = e
ElemAt n (_ ': es) = ElemAt (n - 1) es
class IfNotFound (e :: k) (r :: [k]) (w :: [k])
instance
( TypeError
( 'Text "‘"
':<>: 'ShowType e
':<>: 'Text "’ is not a member of the type-level list"
':$$: 'Text " ‘" ':<>: 'ShowType w ':<>: 'Text "’"
)
)
=> IfNotFound e '[] w
instance IfNotFound e (e ': r) w
instance {-# OVERLAPPABLE #-} (IfNotFound e r w) => IfNotFound e (e' ': r) w
instance {-# INCOHERENT #-} IfNotFound e r w
type LookupError (key :: kk) (w :: [ke]) =
TypeError
( 'Text "The key ‘"
':<>: 'ShowType key
':<>: 'Text "’ does not exist in the type-level list"
':$$: 'Text " ‘" ':<>: 'ShowType w ':<>: 'Text "’"
)
infixr 5 ++
type family xs ++ ys where
'[] ++ ys = ys
(x ': xs) ++ ys = x ': (xs ++ ys)
wordVal :: forall n. (KnownNat n) => Word
wordVal :: forall (n :: Nat). KnownNat n => Word
wordVal = Nat -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Nat -> Word) -> Nat -> Word
forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> *). KnownNat n => proxy n -> Nat
natVal @n Proxy n
forall {k} (t :: k). Proxy t
Proxy
{-# INLINE wordVal #-}
class IsSuffixOf es es' where
prefixLen :: Word
instance IsSuffixOf es es where
prefixLen :: Word
prefixLen = Word
0
instance {-# INCOHERENT #-} (IsSuffixOf es es') => IsSuffixOf es (e ': es') where
prefixLen :: Word
prefixLen = forall (es :: k) (es' :: [a]). IsSuffixOf es es' => Word
forall {k} {k} (es :: k) (es' :: k). IsSuffixOf es es' => Word
prefixLen @es @es' Word -> Word -> Word
forall a. Num a => a -> a -> a
+ Word
1
type family Length es where
Length '[] = 0
Length (e ': es) = 1 + Length es
class (KnownNat (Length es)) => KnownLength es
instance (KnownNat (Length es)) => KnownLength es
reifyLength :: forall es. (KnownLength es) => Word
reifyLength :: forall {a} (es :: [a]). KnownLength es => Word
reifyLength = forall (n :: Nat). KnownNat n => Word
wordVal @(Length es)
{-# INLINE reifyLength #-}
type family PrefixLength es es' where
PrefixLength es es = 0
PrefixLength es (e ': es') = 1 + PrefixLength es es'
type WeakenN len es es' = (es ~ Drop len es', KnownNat len)
type WeakenUnder offset es es' =
(WeakenNUnder (PrefixLength es es') offset es es', KnownNat (PrefixLength es es'))
type WeakenNUnder len offset es es' =
(WeakenN len (Drop offset es) (Drop offset es'), KnownNat offset)
type Strengthen es es' =
(StrengthenMap (PrefixLength es' es) es es', KnownNat (PrefixLength es' es))
type StrengthenN len es es' = (StrengthenMap len es es', KnownNat len)
type StrengthenUnder offset es es' =
(StrengthenNUnder (PrefixLength es' es) offset es es')
type StrengthenNUnder len offset es es' =
(StrengthenMap len (Drop offset es) (Drop offset es'), KnownNat len, KnownNat offset)
type StrengthenMap len es es' = (StrengthenMap_ (len == 0) len es es')
class
(isLenZero ~ (len == 0)) =>
StrengthenMap_ isLenZero len (es :: [k]) (es' :: [k])
where
strengthenMap :: Word -> Word
instance StrengthenMap_ 'True 0 es es where
strengthenMap :: Word -> Word
strengthenMap = Word -> Word
forall a. a -> a
id
{-# INLINE strengthenMap #-}
instance
(StrengthenMap (len - 1) es es', FindElem e es, (len == 0) ~ 'False)
=> StrengthenMap_ 'False len (e ': es) es'
where
strengthenMap :: Word -> Word
strengthenMap = \case
Word
0 -> forall (n :: Nat). KnownNat n => Word
wordVal @(ElemIndex e es)
Word
n -> forall k (isLenZero :: Bool) (len :: Nat) (es :: [k]) (es' :: [k]).
StrengthenMap_ isLenZero len es es' =>
Word -> Word
strengthenMap @_ @_ @(len - 1) @es @es' (Word -> Word) -> Word -> Word
forall a b. (a -> b) -> a -> b
$ Word
n Word -> Word -> Word
forall a. Num a => a -> a -> a
- Word
1
{-# INLINE strengthenMap #-}
strengthenMapUnder :: forall len offset es es'. (StrengthenNUnder len offset es es') => Word -> Word
strengthenMapUnder :: forall {k} (len :: Nat) (offset :: Nat) (es :: [k]) (es' :: [k]).
StrengthenNUnder len offset es es' =>
Word -> Word
strengthenMapUnder = forall k (isLenZero :: Bool) (len :: Nat) (es :: [k]) (es' :: [k]).
StrengthenMap_ isLenZero len es es' =>
Word -> Word
strengthenMap @_ @_ @len @(Drop offset es) @(Drop offset es')
{-# INLINE strengthenMapUnder #-}
type BundleUnder u offset es es' bundle =
( es' ~ Take offset es ++ (u bundle ': Drop (Length bundle) (Drop offset es))
, es ~ Take offset es' ++ bundle ++ Drop 1 (Drop offset es')
, bundle ~ Take (PrefixLength (Drop 1 (Drop offset es')) (Drop offset es)) (Drop offset es)
, KnownLength bundle
, KnownNat offset
, Length bundle ~ PrefixLength (Drop 1 (Drop offset es')) (Drop offset es)
)
type Split es init tail =
( es ~ init ++ tail
, init ~ Take (PrefixLength tail es) es
, tail ~ Drop (Length init) es
, KnownLength init
, Length init ~ PrefixLength tail es
)
type family Take n es where
Take 0 es = '[]
Take n (e ': es) = e ': Take (n - 1) es
type family Drop n es where
Drop 0 es = es
Drop n (e ': es) = Drop (n - 1) es
type Reverse es = Reverse_ '[] es
type family Reverse_ acc es where
Reverse_ acc '[] = acc
Reverse_ acc (e ': es) = Reverse_ (e ': acc) es