checkExpr defs gam pol topLevel tau e = do

  (tau', gam', subst', elaboratedE) <- synthExpr defs gam pol e

  -- Now to do a type equality on check type `tau` and synth type `tau'`
  (tyEq, _, subst) <-
        if topLevel
          -- If we are checking a top-level, then don't allow overapproximation
          then do
            debugM "** Compare for equality " $ pretty tau' <> " = " <> pretty tau
            equalTypesWithPolarity (getSpan e) SndIsSpec tau' tau
          else do
            debugM "** Compare for equality " $ pretty tau' <> " :> " <> pretty tau
            lEqualTypesWithPolarity (getSpan e) SndIsSpec tau' tau

  if tyEq
    then do
      substFinal <- combineSubstitutions (getSpan e) subst subst'
      return (gam', substFinal, elaboratedE)
    else do
      case pol of
        Positive -> throw TypeError{ errLoc = getSpan e, tyExpected = tau , tyActual = tau' }
        Negative -> throw TypeError{ errLoc = getSpan e, tyExpected = tau', tyActual =  tau }

-- | Synthesise the 'Type' of expressions.
-- See <https://en.wikipedia.org/w/index.php?title=Bidirectional_type_checking&redirect=no>
checkExpr defs gam pol topLevel tau e = do

  (tau', gam', subst', elaboratedE) <- synthExpr defs gam pol e

  -- Now to do a type equality on check type `tau` and synth type `tau'`
  (tyEq, _, subst) <-
        if topLevel
          -- If we are checking a top-level, then don't allow overapproximation
          then do
            debugM "** Compare for equality " $ pretty tau' <> " = " <> pretty tau
            equalTypesWithPolarity (getSpan e) SndIsSpec tau' tau
          else do
            debugM "** Compare for equality " $ pretty tau' <> " :> " <> pretty tau
            lEqualTypesWithPolarity (getSpan e) SndIsSpec tau' tau

  if tyEq
    then do
      substFinal <- combineSubstitutions (getSpan e) subst subst'
      return (gam', substFinal, elaboratedE)
    else do
      case pol of
        Positive -> throw TypeError{ errLoc = getSpan e, tyExpected = tau , tyActual = tau' }
        Negative -> throw TypeError{ errLoc = getSpan e, tyExpected = tau', tyActual =  tau }

-- | Synthesise the 'Type' of expressions.
-- See <https://en.wikipedia.org/w/index.php?title=Bidirectional_type_checking&redirect=no>
checkExpr defs gam pol topLevel tau e = do

  (tau', gam', subst', elaboratedE) <- synthExpr defs gam pol e

  -- Now to do a type equality on check type `tau` and synth type `tau'`
  (tyEq, _, subst) <-
        if topLevel
          -- If we are checking a top-level, then don't allow overapproximation
          then do
            debugM "** Compare for equality " $ pretty tau' <> " = " <> pretty tau
            equalTypesWithPolarity (getSpan e) SndIsSpec tau' tau
          else do
            debugM "** Compare for equality " $ pretty tau' <> " :> " <> pretty tau
            lEqualTypesWithPolarity (getSpan e) SndIsSpec tau' tau

  if tyEq
    then do
      substFinal <- combineSubstitutions (getSpan e) subst subst'
      return (gam', substFinal, elaboratedE)
    else do
      case pol of
        Positive -> throw TypeError{ errLoc = getSpan e, tyExpected = tau , tyActual = tau' }
        Negative -> throw TypeError{ errLoc = getSpan e, tyExpected = tau', tyActual =  tau }

-- | Synthesise the 'Type' of expressions.
-- See <https://en.wikipedia.org/w/index.php?title=Bidirectional_type_checking&redirect=no>