{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE PatternGuards #-} -- | Functions for abstracting terms over other terms. module Agda.TypeChecking.Abstract where import Control.Monad import Data.Function import Agda.Syntax.Common hiding (Arg, Dom, NamedArg) import qualified Agda.Syntax.Common as Common import Agda.Syntax.Internal import Agda.TypeChecking.Substitute import Agda.Utils.List (splitExactlyAt) import Agda.Utils.Impossible #include "undefined.h" piAbstractTerm :: Term -> Type -> Type -> Type piAbstractTerm v a b = fun a (abstractTerm v b) where fun a b = El s $ Pi (Common.Dom defaultArgInfo a) $ mkAbs "w" b where s = (sLub `on` getSort) a b -- | @isPrefixOf u v = Just es@ if @v == u `applyE` es@. class IsPrefixOf a where isPrefixOf :: a -> a -> Maybe Elims instance IsPrefixOf Elims where isPrefixOf us vs = do (vs1, vs2) <- splitExactlyAt (length us) vs guard $ us == vs1 return vs2 instance IsPrefixOf Args where isPrefixOf us vs = do (vs1, vs2) <- splitExactlyAt (length us) vs guard $ us == vs1 return $ map Apply vs2 instance IsPrefixOf Term where isPrefixOf u v = case (ignoreSharing u, ignoreSharing v) of (Var i us, Var j vs) | i == j -> us `isPrefixOf` vs (Def f us, Def g vs) | f == g -> us `isPrefixOf` vs (Con c us, Con d vs) | c == d -> us `isPrefixOf` vs (MetaV x us, MetaV y vs) | x == y -> us `isPrefixOf` vs (u, v) -> guard (u == v) >> return [] class AbstractTerm a where -- | @subst u . abstractTerm u == id@ abstractTerm :: Term -> a -> a instance AbstractTerm Term where abstractTerm u v | Just es <- u `isPrefixOf` v = Var 0 $ absT es | otherwise = case v of -- Andreas, 2013-10-20: the original impl. works only at base types -- v | u == v -> Var 0 [] -- incomplete see succeed/WithOfFunctionType Var i vs -> Var (i + 1) $ absT vs Lam h b -> Lam h $ absT b Def c vs -> Def c $ absT vs Con c vs -> Con c $ absT vs Pi a b -> uncurry Pi $ absT (a, b) Lit l -> Lit l Level l -> Level $ absT l Sort s -> Sort $ absT s MetaV m vs -> MetaV m $ absT vs DontCare mv -> DontCare $ absT mv Shared p -> Shared $ absT p ExtLam{} -> __IMPOSSIBLE__ where absT x = abstractTerm u x instance AbstractTerm a => AbstractTerm (Ptr a) where abstractTerm u = fmap (abstractTerm u) instance AbstractTerm Type where abstractTerm u (El s v) = El (abstractTerm u s) (abstractTerm u v) instance AbstractTerm Sort where abstractTerm u s = case s of Type n -> Type $ absS n Prop -> Prop Inf -> Inf SizeUniv -> SizeUniv DLub s1 s2 -> DLub (absS s1) (absS s2) where absS x = abstractTerm u x instance AbstractTerm Level where abstractTerm u (Max as) = Max $ abstractTerm u as instance AbstractTerm PlusLevel where abstractTerm u l@ClosedLevel{} = l abstractTerm u (Plus n l) = Plus n $ abstractTerm u l instance AbstractTerm LevelAtom where abstractTerm u l = case l of MetaLevel m vs -> MetaLevel m $ abstractTerm u vs NeutralLevel r v -> NeutralLevel r $ abstractTerm u v BlockedLevel _ v -> UnreducedLevel $ abstractTerm u v -- abstracting might remove the blockage UnreducedLevel v -> UnreducedLevel $ abstractTerm u v instance AbstractTerm a => AbstractTerm (Elim' a) where abstractTerm = fmap . abstractTerm instance AbstractTerm a => AbstractTerm (Arg a) where abstractTerm = fmap . abstractTerm instance AbstractTerm a => AbstractTerm (Dom a) where abstractTerm = fmap . abstractTerm instance AbstractTerm a => AbstractTerm [a] where abstractTerm = fmap . abstractTerm instance AbstractTerm a => AbstractTerm (Maybe a) where abstractTerm = fmap . abstractTerm instance (Subst a, AbstractTerm a) => AbstractTerm (Abs a) where abstractTerm u (NoAbs x v) = NoAbs x $ abstractTerm u v abstractTerm u (Abs x v) = Abs x $ applySubst swap $ abstractTerm (raise 1 u) v where -- This swaps var 0 and var 1 (we hope) swap = var 1 :# liftS 1 (raiseS 1) instance (AbstractTerm a, AbstractTerm b) => AbstractTerm (a, b) where abstractTerm u (x, y) = (abstractTerm u x, abstractTerm u y)