module Control.Monad.Classes.Exec
  ( MonadExec
  , exec
  , MonadExecN(..)
  , EffExec
  )
  where
import Control.Monad.Trans.Class
import GHC.Prim (Proxy#, proxy#)
import Control.Monad.Classes.Core
import Control.Monad.Classes.Effects
import Data.Peano (Peano (..))

type instance CanDo IO (EffExec IO) = True

class Monad m => MonadExecN (n :: Peano) w m where
  execN :: Proxy# n -> (w a -> m a)

instance Monad w => MonadExecN Zero w w where
  execN _ = id

instance (MonadTrans t, Monad (t m), MonadExecN n w m, Monad m)
  => MonadExecN (Succ n) w (t m)
  where
    execN _ = lift . execN (proxy# :: Proxy# n)

type MonadExec w m = MonadExecN (Find (EffExec w) m) w m

-- | Lift an 'IO' action
exec :: forall w m a . MonadExec w m => w a -> m a
exec = execN (proxy# :: Proxy# (Find (EffExec w) m))