content: --
  -- Adapted from the program "infer", believed to have been originally
  -- authored by Philip Wadler, and used in the nofib benchmark suite
  -- since at least the late 90s.
  --
  
  module Environment
         (Env, emptyEnv, extendLocal, extendGlobal,
          makeEnv, unmakeEnv, lookupEnv, domEnv, freeTVarEnv)
         where
  
  import Shows
  import Term           (VarId)
  import Type
  import Data.Map (Map)
  import Data.Maybe
  import qualified Data.Map as Map
  
  newtype  Env          =   MkEnv (Map VarId PolyType)
  rep                   ::  Env -> Map VarId PolyType
  rep (MkEnv f)         =   f
  emptyEnv              ::  Env
  emptyEnv              =   MkEnv Map.empty
  extendLocal           ::  Env -> VarId -> MonoType -> Env
  extendLocal env x t   =   MkEnv (Map.insert x (All [] t) (rep env))
  extendGlobal          ::  Env -> VarId -> PolyType -> Env
  extendGlobal env x t  =   MkEnv (Map.insert x t (rep env))
  makeEnv               ::  [(VarId, PolyType)] -> Env
  makeEnv               =   MkEnv . Map.fromList
  unmakeEnv             ::  Env -> [(VarId, PolyType)]
  unmakeEnv             =   Map.toList . rep
  lookupEnv             ::  Env -> VarId -> PolyType
  lookupEnv env x       =   fromJust (Map.lookup x (rep env))
  domEnv                ::  Env -> [VarId]
  domEnv env            =   Map.keys (rep env)
  freeTVarEnv           ::  Env -> [TVarId]
  freeTVarEnv env       =   concat (map freeTVarPoly (Map.elems (rep env)))
  instance  Show Env  where
        showsPrec d  =  showsEnv
  showsEnv              :: Shows Env
  showsEnv              =  showsSurround "[" (showsStarSep ",\n " showsPair) "]"
                        .  unmakeEnv
  showsPair             :: Shows (VarId, PolyType)
  showsPair (x,t)       =  showsString x . showsString " : " . shows t
  