Hi I'm looking for a good way to allow a monad stack to skip the remaining actions, without skipping out entirely. Kind of like `return` in C-family langauges. 

For example, let's say I'm using monadic actions for the side effects

```
type MyMonad = ??
doStuff :: MyMonad ()
doStuff = do
   r <- doSomething

   -- equivalent to if (r == "X") return; in C
   dontGoPastHereIf (r == "X")

   doSomeSideEffects r

```

So I want it to only perform `doSomeSideEffects` on some condition. 

I know you can do something close to this with `guard` and `when` already. Is it possible to do without nesting though?

`ExceptT` already allows you to exit the normal flow and return with an early result. But with `ExceptT` the error / skip will propogate. I want to only skip the rest of the steps in the local function

```
doTwoSteps :: MyMonad ()
doTwoSteps = do
  -- if I used ExceptT, an error in the first function will skip the second.
  -- But I still want to do the second step here
  doStuff
  doStuff

```

It seems like bind `>>=` already does this. At least it's certainly within the possibilities of a monad, but I'm not sure how to do with monad transformers. 

---

Here's a more complete example. This system is supposed to perform a "workflow". Each step can result in a response, which is supposed to stop the entire workflow and respond (`ExceptT`).

The workflow can be restarted by passing `ApplicationState`. If a step has a previous `Continue` we can skip the logic for that step, but we still need to execute the next step. 

Is there a better way to do this? Is there some monad transformer or a way to define my `Flow` monad such that I can run `checkShouldSkip` without passing in an action?

```
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}

module Main where

import Control.Monad.Except (throwError, ExceptT)
import Control.Monad.State (gets, StateT, modify)
import Data.Text (Text)

data ApplicationState = ApplicationState
    { step1Result :: Maybe StepResult
    , step2Result :: Maybe StepResult
    } deriving (Show, Eq)

data StepResult
    = Stop
    | Continue
    deriving (Show, Eq)

type Flow a = StateT ApplicationState (ExceptT Text IO) a

flow :: Flow ()
flow = do
    step1
    step2

step1 :: Flow ()
step1 = do
    ms <- gets step1Result
    checkShouldSkip ms $ do
      info <- getStuffFromAServer
      let r = runSomeLogic info
      modify $ setStep1 $ Just r
      checkShouldRespond r

  where
    getStuffFromAServer = undefined
    runSomeLogic _ = undefined
    setStep1 r s = s { step1Result = r }

step2 :: Flow ()
step2 = do
    ms <- gets step2Result
    checkShouldSkip ms $ do
      -- this will run some different logic, eventually resulting in a step result
      r <- getStuffAndRunLogic
      modify $ setStep2 $ Just r
      checkShouldRespond r

  where
    getStuffAndRunLogic = undefined
    setStep2 r s = s { step2Result = r }

checkShouldSkip :: Maybe StepResult -> Flow () -> Flow ()
checkShouldSkip (Just Continue) _ = pure () -- skip the logic, continue
checkShouldSkip (Just Stop) _ = respond "Stop" -- skip the logic, stop everything
checkShouldSkip Nothing a = a -- run the action

checkShouldRespond :: StepResult -> Flow ()
checkShouldRespond Continue = pure ()
checkShouldRespond Stop = respond "Stop" -- if a response, stop all execution

-- rename because these aren't really errors, I just want to stop everything
respond :: Text -> Flow ()
respond t = throwError t

```