Creating a Stripe Subscription I have some working Haskell code in a Yesod application that is responsible for creating a new paid Stripe subscription for a user.

Although it works, I'm not pleased with the walking indentation that appears as a result of nested Either case matches.

module Handler.Purchase where

import           Import
import           Web.Stripe
import           Web.Stripe.Customer
import           Web.Stripe.Plan
import           Web.Stripe.Subscription

postPurchaseR :: Handler Html
postPurchaseR = do
  -- I will need to keep a reference to the user later
  _ &lt;- requireAuth

  -- I will need to keep a reference to the Stripe token later
  _ &lt;- runInputPost $ ireq textField "stripeToken"

  -- I hard-code the secret key, which I'm fine with for now
  let config = StripeConfig $ StripeKey "&lt;redacted&gt;"

  -- Here's where things get hairy...
  customer &lt;- liftIO $ stripe config createCustomer
  case customer of
    Left err -&gt; do
      setMessage $ toHtml $ show err
      redirect (AppR :#: ("subscribe" :: Text))
    Right Customer { customerId = cid } -&gt; do
      plan &lt;- liftIO $ stripe config $ getPlan (PlanId "PRO")
      case plan of
        Left err -&gt; do
          setMessage $ toHtml $ show err
          redirect (AppR :#: ("subscribe" :: Text))
        Right Plan { planId = pid } -&gt; do
          subscription &lt;- liftIO $ stripe config $ createSubscription cid pid
          case subscription of
            Left err -&gt; do
              setMessage $ toHtml $ show err
              redirect (AppR :#: ("subscribe" :: Text))
            Right _ -&gt; do
              setMessage "Subscription successful. Thanks!"
              redirect AppR


As I understand it, I should be using ExceptT instead of having all that nesting, but I'm not sure how that works. Correct use of ExceptT will probably obviate the need for me to define how to handle those three failures each time.
Here is how you can use ExceptT:

  -- I hard-code the secret key, which I'm fine with for now
  let config = StripeConfig $ StripeKey "&lt;redacted&gt;"
  let stripe' :: (FromJSON (StripeReturn a))
              =&gt; StripeRequest a -&gt; ExceptT StripeError Handler (StripeReturn a)
      stripe' = ExceptT . liftIO . stripe config

  -- Here's where things get hairy...
  r &lt;- runExceptT $ do
    Customer {..} &lt;- stripe' createCustomer
    Plan {..} &lt;- stripe' $ getPlan (PlanId "PRO")
    stripe' $ createSubscription customerId planId
  case r of
    Left err -&gt; do
      setMessage $ toHtml $ show err
      redirect (AppR :#: ("subscribe" :: Text))
    Right _ -&gt; do
      setMessage "Subscription successful. Thanks!"
      redirect AppR


I used RecordWildcards so that the intermediate variables (e.g. cid and pid) aren't necessary. 
You'll also need to enable FlexibleContexts because of the way stripe is defined in the library.