title: Skip the remaining actions in a monad - like return
body: <p>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 <code>return</code> in C-family langauges. </p>
  
  <p>For example, let's say I'm using monadic actions for the side effects</p>
  
  <pre><code>type MyMonad = ??
  doStuff :: MyMonad ()
  doStuff = do
     r &lt;- doSomething
  
     -- equivalent to if (r == "X") return; in C
     dontGoPastHereIf (r == "X")
  
     doSomeSideEffects r
  </code></pre>
  
  <p>So I want it to only perform <code>doSomeSideEffects</code> on some condition. </p>
  
  <p>I know you can do something close to this with <code>guard</code> and <code>when</code> already. Is it possible to do without nesting though?</p>
  
  <p><code>ExceptT</code> already allows you to exit the normal flow and return with an early result. But with <code>ExceptT</code> the error / skip will propogate. I want to only skip the rest of the steps in the local function</p>
  
  <pre><code>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
  </code></pre>
  
  <p>It seems like bind <code>&gt;&gt;=</code> 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. </p>
  
  <hr>
  
  <p>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 (<code>ExceptT</code>).</p>
  
  <p>The workflow can be restarted by passing <code>ApplicationState</code>. If a step has a previous <code>Continue</code> we can skip the logic for that step, but we still need to execute the next step. </p>
  
  <p>Is there a better way to do this? Is there some monad transformer or a way to define my <code>Flow</code> monad such that I can run <code>checkShouldSkip</code> without passing in an action?</p>
  
  <pre><code>{-# 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 &lt;- gets step1Result
      checkShouldSkip ms $ do
        info &lt;- 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 &lt;- gets step2Result
      checkShouldSkip ms $ do
        -- this will run some different logic, eventually resulting in a step result
        r &lt;- getStuffAndRunLogic
        modify $ setStep2 $ Just r
        checkShouldRespond r
  
    where
      getStuffAndRunLogic = undefined
      setStep2 r s = s { step2Result = r }
  
  
  checkShouldSkip :: Maybe StepResult -&gt; Flow () -&gt; 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 -&gt; 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 -&gt; Flow ()
  respond t = throwError t
  </code></pre>