{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}
module Control.Monad.Trans.Uplift
( uplift
, Substack(..)
, Uplift
, IndexOf
, N(..)
) where
import Control.Monad.Trans (MonadTrans(lift))
data N = S N | Z
type family Substack n f where
Substack 'Z f = f
Substack ('S n) (t f) = Substack n f
class Uplift n f where
liftSubstack :: Substack n f a -> f a
instance Uplift 'Z f where
liftSubstack = id
instance (Monad f, MonadTrans t, Uplift n f) => Uplift ('S n) (t f) where
liftSubstack = lift . liftSubstack @n
type family IndexOf t f where
IndexOf t (t f) = 'Z
IndexOf t (t' f) = 'S (IndexOf t f)
uplift :: forall t f a. Uplift (IndexOf t f) f => Substack (IndexOf t f) f a -> f a
uplift = liftSubstack @(IndexOf t f)