{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Control.Monad.Stack.Internal
( module Control.Monad.Stack.Internal
, module GHC.TypeNats
) where
import Data.Constraint
import Data.Kind
import Data.Proxy
import Data.Type.Equality
import GHC.TypeNats
import Unsafe.Coerce
type family Pop (c :: k) (m :: k') :: k'
type family IteratePop (n :: Nat) (c :: k) (m :: Type -> Type) :: Type -> Type where
IteratePop 0 c m = m
IteratePop n c m = IteratePop (n-1) c (Pop c m)
type family StackConstraints (n :: Nat) (c :: k) (cSucc :: k' -> Constraint) (m :: k') :: Constraint where
StackConstraints 0 c cSucc m = ()
StackConstraints n c cSucc m = (cSucc m, StackConstraints (n-1) c cSucc (Pop c m))
predNat :: forall n. KnownNat n => Either (n :~: 0) (Dict (KnownNat (n-1)))
predNat = case sameNat (Proxy @0) (Proxy @n) of
Just Refl -> Left Refl
Nothing -> case someNatVal (natVal @n Proxy - 1) of
SomeNat p -> Right (unsafeCoerce (wrap p))
where
wrap :: KnownNat n' => Proxy n' -> Dict (KnownNat n')
wrap _ = Dict
nonZeroNat :: forall n c cSucc m a.
KnownNat (n-1) =>
( IteratePop n c m a :~: IteratePop (n-1) c (Pop c m) a
, StackConstraints n c cSucc m :~: (cSucc m, StackConstraints (n-1) c cSucc (Pop c m))
)
nonZeroNat = unsafeCoerce (Refl, Refl)
depth :: forall n c cSucc m a.
(KnownNat n, StackConstraints n c cSucc m) =>
(forall m. cSucc m => Pop c m a -> m a) ->
IteratePop n c m a ->
m a
depth lift act = case predNat @n of
Left Refl -> act
Right Dict -> case nonZeroNat @n @c @cSucc @m of
(Refl, Refl) -> lift (depth @(n-1) @c @cSucc lift act)
data ContTag