• Jump To … +
    CTT.hs Connections.hs Eval.hs Exp/Abs.hs Exp/ErrM.hs Exp/Layout.hs Exp/Print.hs Exp/Skel.hs Exp/Test.hs Main.hs Resolver.hs Setup.hs TypeChecker.hs
  • Resolver.hs

  • §
    {-# LANGUAGE TupleSections #-}
  • §

    | Convert the concrete syntax into the syntax of cubical TT.

    module Resolver(
         Resolver
       , resolveModule
       , resolveModules
       , SymKind(..)
       , runResolver
       , resolveExp
       , insertIdents) where
    
    import Control.Applicative
    import Control.Monad
    import Control.Monad.Reader
    import Control.Monad.Except
    import Control.Monad.Identity
    import Data.Maybe
    import Data.List
    import Data.Map (Map,(!))
    import qualified Data.Map as Map
    
    import Exp.Abs
    import CTT (Ter,Ident,Loc(..),mkApps,mkWheres)
    import qualified CTT
    import Connections (negFormula,andFormula,orFormula)
    import qualified Connections as C
  • §

    | Useful auxiliary functions

  • §

    Applicative cons

    (<:>) :: Applicative f => f a -> f [a] -> f [a]
    a <:> b = (:) <$> a <*> b
  • §

    Un-something functions

    unVar :: Exp -> Maybe Ident
    unVar (Var (AIdent (_,x))) = Just x
    unVar _                    = Nothing
    
    unWhere :: ExpWhere -> Exp
    unWhere (Where e ds) = Let ds e
    unWhere (NoWhere e)  = e
  • §

    Tail recursive form to transform a sequence of applications App (App (App u v) …) w into (u, [v, …, w]) (cleaner than the previous version of unApps)

    unApps :: Exp -> [Exp] -> (Exp, [Exp])
    unApps (App u v) ws = unApps u (v : ws)
    unApps u         ws = (u, ws)
  • §

    Turns an expression of the form App (… (App id1 id2) … idn) into a list of idents

    appsToIdents :: Exp -> Maybe [Ident]
    appsToIdents = mapM unVar . uncurry (:) . flip unApps []
  • §

    Transform a sequence of applications (((u v1) .. vn) phi1) .. phim into (u,[v1,..,vn],[phi1,..,phim])

    unAppsFormulas :: Exp -> [Formula]-> (Exp,[Exp],[Formula])
    unAppsFormulas (AppFormula u phi) phis = unAppsFormulas u (phi:phis)
    unAppsFormulas u phis = (x,xs,phis)
      where (x,xs) = unApps u []
  • §

    Flatten a tele

    flattenTele :: [Tele] -> [(Ident,Exp)]
    flattenTele tele =
      [ (unAIdent i,typ) | Tele id ids typ <- tele, i <- id:ids ]
  • §

    Flatten a PTele

    flattenPTele :: [PTele] -> Resolver [(Ident,Exp)]
    flattenPTele []                   = return []
    flattenPTele (PTele exp typ : xs) = case appsToIdents exp of
      Just ids -> do
        pt <- flattenPTele xs
        return $ map (,typ) ids ++ pt
      Nothing -> throwError "malformed ptele"
  • §

  • §

    | Resolver and environment

    data SymKind = Variable | Constructor | PConstructor | Name
      deriving (Eq,Show)
  • §

    local environment for constructors

    data Env = Env { envModule :: String,
                     variables :: [(Ident,SymKind)] }
      deriving (Eq,Show)
    
    type Resolver a = ReaderT Env (Except String) a
    
    emptyEnv :: Env
    emptyEnv = Env "" []
    
    runResolver :: Resolver a -> Either String a
    runResolver x = runIdentity $ runExceptT $ runReaderT x emptyEnv
    
    updateModule :: String -> Env -> Env
    updateModule mod e = e{envModule = mod}
    
    insertIdent :: (Ident,SymKind) -> Env -> Env
    insertIdent (n,var) e
      | n == "_"  = e
      | otherwise = e{variables = (n,var) : variables e}
    
    insertIdents :: [(Ident,SymKind)] -> Env -> Env
    insertIdents = flip $ foldr insertIdent
    
    insertName :: AIdent -> Env -> Env
    insertName (AIdent (_,x)) = insertIdent (x,Name)
    
    insertNames :: [AIdent] -> Env -> Env
    insertNames = flip $ foldr insertName
    
    insertVar :: Ident -> Env -> Env
    insertVar x = insertIdent (x,Variable)
    
    insertVars :: [Ident] -> Env -> Env
    insertVars = flip $ foldr insertVar
    
    insertAIdent :: AIdent -> Env -> Env
    insertAIdent (AIdent (_,x)) = insertIdent (x,Variable)
    
    insertAIdents :: [AIdent] -> Env -> Env
    insertAIdents  = flip $ foldr insertAIdent
    
    getLoc :: (Int,Int) -> Resolver Loc
    getLoc l = Loc <$> asks envModule <*> pure l
    
    unAIdent :: AIdent -> Ident
    unAIdent (AIdent (_,x)) = x
    
    resolveName :: AIdent -> Resolver C.Name
    resolveName (AIdent (l,x)) = do
      modName <- asks envModule
      vars <- asks variables
      case lookup x vars of
        Just Name -> return $ C.Name x
        _ -> throwError $ "Cannot resolve name " ++ x ++ " at position " ++
                          show l ++ " in module " ++ modName
    
    resolveVar :: AIdent -> Resolver Ter
    resolveVar (AIdent (l,x)) = do
      modName <- asks envModule
      vars    <- asks variables
      case lookup x vars of
        Just Variable    -> return $ CTT.Var x
        Just Constructor -> return $ CTT.Con x []
        Just PConstructor ->
          throwError $ "The path constructor " ++ x ++ " is used as a" ++
                       " variable at " ++ show l ++ " in " ++ modName ++
                       " (path constructors should have their type in" ++
                       " curly braces as first argument)"
        Just Name        ->
          throwError $ "Name " ++ x ++ " used as a variable at position " ++
                       show l ++ " in module " ++ modName
        _ -> throwError $ "Cannot resolve variable " ++ x ++ " at position " ++
                          show l ++ " in module " ++ modName
    
    lam :: (Ident,Exp) -> Resolver Ter -> Resolver Ter
    lam (a,t) e = CTT.Lam a <$> resolveExp t <*> local (insertVar a) e
    
    lams :: [(Ident,Exp)] -> Resolver Ter -> Resolver Ter
    lams = flip $ foldr lam
    
    plam :: AIdent -> Resolver Ter -> Resolver Ter
    plam i e = CTT.PLam (C.Name (unAIdent i)) <$> local (insertName i) e
    
    plams :: [AIdent] -> Resolver Ter -> Resolver Ter
    plams [] _ = throwError "Empty plam abstraction"
    plams xs e = foldr plam e xs
    
    bind :: (Ter -> Ter) -> (Ident,Exp) -> Resolver Ter -> Resolver Ter
    bind f (x,t) e = f <$> lam (x,t) e
    
    binds :: (Ter -> Ter) -> [(Ident,Exp)] -> Resolver Ter -> Resolver Ter
    binds f = flip $ foldr $ bind f
    
    resolveApps :: Exp -> [Exp] -> Resolver Ter
    resolveApps x xs = mkApps <$> resolveExp x <*> mapM resolveExp xs
    
    resolveExp :: Exp -> Resolver Ter
    resolveExp e = case e of
      U             -> return CTT.U
      Var x         -> resolveVar x
      App t s       -> resolveApps x xs
        where (x,xs) = unApps t [s]
      Sigma ptele b -> do
        tele <- flattenPTele ptele
        binds CTT.Sigma tele (resolveExp b)
      Pi ptele b    -> do
        tele <- flattenPTele ptele
        binds CTT.Pi tele (resolveExp b)
      Fun a b       -> bind CTT.Pi ("_",a) (resolveExp b)
      Lam ptele t   -> do
        tele <- flattenPTele ptele
        lams tele (resolveExp t)
      Fst t         -> CTT.Fst <$> resolveExp t
      Snd t         -> CTT.Snd <$> resolveExp t
      Pair t0 ts    -> do
        e  <- resolveExp t0
        es <- mapM resolveExp ts
        return $ foldr1 CTT.Pair (e:es)
      Split t brs -> do
        t'   <- resolveExp t
        brs' <- mapM resolveBranch brs
        l@(Loc n (i,j)) <- getLoc (case brs of
                                      OBranch (AIdent (l,_)) _ _:_ -> l
                                      PBranch (AIdent (l,_)) _ _ _:_ -> l
                                      _ -> (0,0))
        return $ CTT.Split (n ++ "_L" ++ show i ++ "_C" ++ show j) l t' brs'
      Let decls e   -> do
        (rdecls,names) <- resolveDecls decls
        mkWheres rdecls <$> local (insertIdents names) (resolveExp e)
      PLam is e     -> plams is (resolveExp e)
      Hole (HoleIdent (l,_)) -> CTT.Hole <$> getLoc l
      AppFormula t phi ->
        let (x,xs,phis) = unAppsFormulas e []
        in case x of
          PCon n a ->
            CTT.PCon (unAIdent n) <$> resolveExp a <*> mapM resolveExp xs
                                  <*> mapM resolveFormula phis
          _ -> CTT.AppFormula <$> resolveExp t <*> resolveFormula phi
      PathP a u v   -> CTT.PathP <$> resolveExp a <*> resolveExp u <*> resolveExp v
      Comp u v ts   -> CTT.Comp <$> resolveExp u <*> resolveExp v <*> resolveSystem ts
      HComp u v ts  -> CTT.HComp <$> resolveExp u <*> resolveExp v <*> resolveSystem ts
      Fill u v ts   -> CTT.Fill <$> resolveExp u <*> resolveExp v <*> resolveSystem ts
      Trans u v     -> CTT.Comp <$> resolveExp u <*> resolveExp v <*> pure Map.empty
      Glue u ts     -> CTT.Glue <$> resolveExp u <*> resolveSystem ts
      GlueElem u ts -> CTT.GlueElem <$> resolveExp u <*> resolveSystem ts
      UnGlueElem u ts -> CTT.UnGlueElem <$> resolveExp u <*> resolveSystem ts
      Id a u v      -> CTT.Id <$> resolveExp a <*> resolveExp u <*> resolveExp v
      IdPair u ts   -> CTT.IdPair <$> resolveExp u <*> resolveSystem ts
      IdJ a t c d x p -> CTT.IdJ <$> resolveExp a <*> resolveExp t <*> resolveExp c
                                 <*> resolveExp d <*> resolveExp x <*> resolveExp p
      _ -> do
        modName <- asks envModule
        throwError ("Could not resolve " ++ show e ++ " in module " ++ modName)
    
    resolveWhere :: ExpWhere -> Resolver Ter
    resolveWhere = resolveExp . unWhere
    
    resolveSystem :: System -> Resolver (C.System Ter)
    resolveSystem (System ts) = do
      ts' <- sequence [ (,) <$> resolveFace alpha <*> resolveExp u
                      | Side alpha u <- ts ]
      let alphas = map fst ts'
      unless (nub alphas == alphas) $
        throwError $ "system contains same face multiple times: " ++
                     C.showListSystem ts'
  • §

    Note: the symbols in alpha are in scope in u, but they mean 0 or 1

      return $ Map.fromList ts'
    
    resolveFace :: [Face] -> Resolver C.Face
    resolveFace alpha =
      Map.fromList <$> sequence [ (,) <$> resolveName i <*> resolveDir d
                                | Face i d <- alpha ]
    
    resolveDir :: Dir -> Resolver C.Dir
    resolveDir Dir0 = return 0
    resolveDir Dir1 = return 1
    
    resolveFormula :: Formula -> Resolver C.Formula
    resolveFormula (Dir d)          = C.Dir <$> resolveDir d
    resolveFormula (Atom i)         = C.Atom <$> resolveName i
    resolveFormula (Neg phi)        = negFormula <$> resolveFormula phi
    resolveFormula (Conj phi _ psi) =
        andFormula <$> resolveFormula phi <*> resolveFormula psi
    resolveFormula (Disj phi psi)   =
        orFormula <$> resolveFormula phi <*> resolveFormula psi
    
    resolveBranch :: Branch -> Resolver CTT.Branch
    resolveBranch (OBranch (AIdent (_,lbl)) args e) = do
      re <- local (insertAIdents args) $ resolveWhere e
      return $ CTT.OBranch lbl (map unAIdent args) re
    resolveBranch (PBranch (AIdent (_,lbl)) args is e) = do
      re <- local (insertNames is . insertAIdents args) $ resolveWhere e
      let names = map (C.Name . unAIdent) is
      return $ CTT.PBranch lbl (map unAIdent args) names re
    
    resolveTele :: [(Ident,Exp)] -> Resolver CTT.Tele
    resolveTele []        = return []
    resolveTele ((i,d):t) =
      ((i,) <$> resolveExp d) <:> local (insertVar i) (resolveTele t)
    
    resolveLabel :: [(Ident,SymKind)] -> Label -> Resolver CTT.Label
    resolveLabel _ (OLabel n vdecl) =
      CTT.OLabel (unAIdent n) <$> resolveTele (flattenTele vdecl)
    resolveLabel cs (PLabel n vdecl is sys) = do
      let tele' = flattenTele vdecl
          ts    = map fst tele'
          names = map (C.Name . unAIdent) is
          n'    = unAIdent n
          cs'   = delete (n',PConstructor) cs
      CTT.PLabel n' <$> resolveTele tele' <*> pure names
                    <*> local (insertNames is . insertIdents cs' . insertVars ts)
                          (resolveSystem sys)
  • §

    Resolve a non-mutual declaration; returns resolver for type and body separately

    resolveNonMutualDecl :: Decl -> (Ident,Resolver CTT.Ter
                                    ,Resolver CTT.Ter,[(Ident,SymKind)])
    resolveNonMutualDecl d = case d of
      DeclDef (AIdent (_,f)) tele t body ->
        let tele' = flattenTele tele
            a     = binds CTT.Pi tele' (resolveExp t)
            d     = lams tele' (local (insertVar f) $ resolveWhere body)
        in (f,a,d,[(f,Variable)])
      DeclData x tele sums  -> resolveDeclData x tele sums null
      DeclHData x tele sums ->
        resolveDeclData x tele sums (const False) -- always pick HSum
      DeclSplit (AIdent (l,f)) tele t brs ->
        let tele' = flattenTele tele
            vars  = map fst tele'
            a     = binds CTT.Pi tele' (resolveExp t)
            d     = do
                      loc <- getLoc l
                      ty  <- local (insertVars vars) $ resolveExp t
                      brs' <- local (insertVars (f:vars)) (mapM resolveBranch brs)
                      lams tele' (return $ CTT.Split f loc ty brs')
        in (f,a,d,[(f,Variable)])
      DeclUndef (AIdent (l,f)) tele t ->
        let tele' = flattenTele tele
            a     = binds CTT.Pi tele' (resolveExp t)
            d     = CTT.Undef <$> getLoc l <*> a
        in (f,a,d,[(f,Variable)])
  • §

    Helper function to resolve data declarations. The predicate p is used to decide if we should use Sum or HSum.

    resolveDeclData :: AIdent -> [Tele] -> [Label] -> ([(Ident,SymKind)] -> Bool) ->
                       (Ident, Resolver Ter, Resolver Ter, [(Ident, SymKind)])
    resolveDeclData (AIdent (l,f)) tele sums p =
      let tele' = flattenTele tele
          a     = binds CTT.Pi tele' (return CTT.U)
          cs    = [ (unAIdent lbl,Constructor) | OLabel lbl _ <- sums ]
          pcs   = [ (unAIdent lbl,PConstructor) | PLabel lbl _ _ _ <- sums ]
          sum   = if p pcs then CTT.Sum else CTT.HSum
          d = lams tele' $ local (insertVar f) $
                sum <$> getLoc l <*> pure f
                    <*> mapM (resolveLabel (cs ++ pcs)) sums
      in (f,a,d,(f,Variable):cs ++ pcs)
    
    resolveRTele :: [Ident] -> [Resolver CTT.Ter] -> Resolver CTT.Tele
    resolveRTele [] _ = return []
    resolveRTele (i:is) (t:ts) = do
      a  <- t
      as <- local (insertVar i) (resolveRTele is ts)
      return ((i,a):as)
  • §

    Best effort to find the location of a declaration. This implementation returns the location of the first identifier it contains.

    findDeclLoc :: Decl -> Resolver Loc
    findDeclLoc d = getLoc loc
        where loc = fromMaybe (-1, 0) $ mloc d
              mloc d = case d of
                DeclDef (AIdent (l, _)) _ _ _   -> Just l
                DeclData (AIdent (l, _)) _ _    -> Just l
                DeclHData (AIdent (l, _)) _ _   -> Just l
                DeclSplit (AIdent (l, _)) _ _ _ -> Just l
                DeclUndef (AIdent (l, _)) _ _   -> Just l
                DeclMutual ds                   -> listToMaybe $ mapMaybe mloc ds
                DeclOpaque (AIdent (l, _))      -> Just l
                DeclTransparent (AIdent (l, _)) -> Just l
                DeclTransparentAll              -> Nothing
  • §

    Resolve a declaration

    resolveDecl :: Decl -> Resolver (CTT.Decls,[(Ident,SymKind)])
    resolveDecl d = case d of
      DeclMutual decls -> do
        let (fs,ts,bs,nss) = unzip4 $ map resolveNonMutualDecl decls
            ns = concat nss -- TODO: some sanity checks? Duplicates!?
        when (nub (map fst ns) /= concatMap (map fst) nss) $
          throwError ("Duplicated constructor or ident: " ++ show nss)
        as <- resolveRTele fs ts
  • §

    The bodies know about all the names and constructors in the mutual block

        ds <- sequence $ map (local (insertIdents ns)) bs
        let ads = zipWith (\ (x,y) z -> (x,(y,z))) as ds
        l <- findDeclLoc d
        return (CTT.MutualDecls l ads,ns)
      DeclOpaque i  -> do
        resolveVar i
        return (CTT.OpaqueDecl (unAIdent i), [])
      DeclTransparent i -> do
        resolveVar i
        return (CTT.TransparentDecl (unAIdent i), [])
      DeclTransparentAll -> return (CTT.TransparentAllDecl, [])
      _ -> do let (f,typ,body,ns) = resolveNonMutualDecl d
              l <- findDeclLoc d
              a <- typ
              d <- body
              return (CTT.MutualDecls l [(f,(a,d))],ns)
    
    resolveDecls :: [Decl] -> Resolver ([CTT.Decls],[(Ident,SymKind)])
    resolveDecls []     = return ([],[])
    resolveDecls (d:ds) = do
      (rtd,names)  <- resolveDecl d
      (rds,names') <- local (insertIdents names) $ resolveDecls ds
      return (rtd : rds, names' ++ names)
    
    resolveModule :: Module -> Resolver ([CTT.Decls],[(Ident,SymKind)])
    resolveModule (Module (AIdent (_,n)) _ decls) =
      local (updateModule n) $ resolveDecls decls
    
    resolveModules :: [Module] -> Resolver ([CTT.Decls],[(Ident,SymKind)])
    resolveModules []         = return ([],[])
    resolveModules (mod:mods) = do
      (rmod, names)  <- resolveModule mod
      (rmods,names') <- local (insertIdents names) $ resolveModules mods
      return (rmod ++ rmods, names' ++ names)