module Problem3 where

import Control.Monad.Reader

-- a)

newtype TC a = TC { runTC :: ReaderT Context (Either String) a }
  deriving (Monad, MonadError String, MonadReader Context)

-- b)

lookupVar :: Name -> TC Type
lookupVar x = do
  cxt <- ask
  case varType x cxt of
    Nothing -> typeError $ "not in scope: " ++ show x
    Just t  -> return t

extendContext :: Name -> Type -> TC a -> TC a
extendContext x t = local (addVar x t)

-- c)

infer (Var x) = lookupVar x
infer (Let x e1 e2) = do
  t1 <- infer e1
  extendContext x t1 (infer e2)