synthExpr defs gam _ (Val s _ (Var _ x)) =
   -- Try the local context
   case lookup x gam of
     Nothing ->
       -- Try definitions in scope
       case lookup x (defs <> Primitives.builtins) of
         Just tyScheme  -> do
           (ty', _, _, constraints, []) <- freshPolymorphicInstance InstanceQ False tyScheme [] -- discard list of fresh type variables

           mapM_ (\ty -> do
             pred <- compileTypeConstraintToConstraint s ty
             addPredicate pred) constraints

           let elaborated = Val s ty' (Var ty' x)
           return (ty', [], [], elaborated)

         -- Couldn't find it
         Nothing -> throw UnboundVariableError{ errLoc = s, errId = x }

     -- In the local context
     Just (Linear ty)       -> do
       let elaborated = Val s ty (Var ty x)
       return (ty, [(x, Linear ty)], [], elaborated)

     Just (Discharged ty c) -> do
       k <- inferCoeffectType s c
       let elaborated = Val s ty (Var ty x)
       return (ty, [(x, Discharged ty (COne k))], [], elaborated)

-- Specialised application for scale
{-
TODO: needs thought
synthExpr defs gam pol
      (App _ _ (Val _ _ (Var _ v)) (Val _ _ (NumFloat _ r))) | internalName v == "scale" = do
  let float = TyCon $ mkId "Float"
  return (FunTy (Box (CFloat (toRational r)) float) float, [])
-}

-- Application
synthExpr defs gam _ (Val s _ (Var _ x)) =
   -- Try the local context
   case lookup x gam of
     Nothing ->
       -- Try definitions in scope
       case lookup x (defs <> Primitives.builtins) of
         Just tyScheme  -> do
           (ty', _, _, constraints, []) <- freshPolymorphicInstance InstanceQ False tyScheme [] -- discard list of fresh type variables

           mapM_ (\ty -> do
             pred <- compileTypeConstraintToConstraint s ty
             addPredicate pred) constraints

           let elaborated = Val s ty' (Var ty' x)
           return (ty', [], [], elaborated)

         -- Couldn't find it
         Nothing -> throw UnboundVariableError{ errLoc = s, errId = x }

     -- In the local context
     Just (Linear ty)       -> do
       let elaborated = Val s ty (Var ty x)
       return (ty, [(x, Linear ty)], [], elaborated)

     Just (Discharged ty c) -> do
       k <- inferCoeffectType s c
       let elaborated = Val s ty (Var ty x)
       return (ty, [(x, Discharged ty (COne k))], [], elaborated)

-- Specialised application for scale
{-
TODO: needs thought
synthExpr defs gam pol
      (App _ _ (Val _ _ (Var _ v)) (Val _ _ (NumFloat _ r))) | internalName v == "scale" = do
  let float = TyCon $ mkId "Float"
  return (FunTy (Box (CFloat (toRational r)) float) float, [])
-}

-- Application
synthExpr defs gam _ (Val s _ (Var _ x)) =
   -- Try the local context
   case lookup x gam of
     Nothing ->
       -- Try definitions in scope
       case lookup x (defs <> Primitives.builtins) of
         Just tyScheme  -> do
           (ty', _, _, constraints, []) <- freshPolymorphicInstance InstanceQ False tyScheme [] -- discard list of fresh type variables

           mapM_ (\ty -> do
             pred <- compileTypeConstraintToConstraint s ty
             addPredicate pred) constraints

           let elaborated = Val s ty' (Var ty' x)
           return (ty', [], [], elaborated)

         -- Couldn't find it
         Nothing -> throw UnboundVariableError{ errLoc = s, errId = x }

     -- In the local context
     Just (Linear ty)       -> do
       let elaborated = Val s ty (Var ty x)
       return (ty, [(x, Linear ty)], [], elaborated)

     Just (Discharged ty c) -> do
       k <- inferCoeffectType s c
       let elaborated = Val s ty (Var ty x)
       return (ty, [(x, Discharged ty (COne k))], [], elaborated)

-- Specialised application for scale
{-
TODO: needs thought
synthExpr defs gam pol
      (App _ _ (Val _ _ (Var _ v)) (Val _ _ (NumFloat _ r))) | internalName v == "scale" = do
  let float = TyCon $ mkId "Float"
  return (FunTy (Box (CFloat (toRational r)) float) float, [])
-}

-- Application