{-# LANGUAGE DerivingVia #-} module SC.Monad where import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.Except import Control.Monad.Trans.State.Strict newtype SC a = SC (ExceptT String (State Int) a) deriving (Functor, Applicative, Monad) via (ExceptT String (State Int)) instance MonadFail SC where fail = throw evalSC :: SC a -> Either String a evalSC (SC m) = evalState (runExceptT m) 1 genId :: SC Int genId = SC $ do value <- lift get lift (modify (+1)) return value throw :: String -> SC a throw = SC . throwE