{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} module Agda.Syntax.Internal ( module Agda.Syntax.Internal , module Agda.Syntax.Abstract.Name , module Agda.Utils.Pointer ) where import Prelude hiding (foldr, mapM, null) import Control.Arrow ((***)) import Control.Applicative hiding (empty) import Control.Monad.Identity hiding (mapM) import Control.Monad.State hiding (mapM) import Control.Parallel import Data.Foldable ( Foldable, foldMap ) import Data.Function import qualified Data.List as List import Data.Maybe import Data.Monoid -- base-4.7 defines the Num instance for Sum #if !(MIN_VERSION_base(4,7,0)) import Data.Orphans () #endif import Data.Traversable import Data.Typeable (Typeable) import Agda.Syntax.Position import Agda.Syntax.Common hiding (Arg, Dom, NamedArg, ArgInfo) import qualified Agda.Syntax.Common as Common import Agda.Syntax.Literal import Agda.Syntax.Abstract (IsProjP(..)) import Agda.Syntax.Abstract.Name import Agda.Utils.Empty -- See Issue 1593. #if !MIN_VERSION_transformers(0,4,1) import Agda.Utils.Except ( Error(noMsg) ) #endif import Agda.Utils.Functor import Agda.Utils.Geniplate import Agda.Utils.Lens import Agda.Utils.List import Agda.Utils.Null import Agda.Utils.Permutation import Agda.Utils.Pointer import Agda.Utils.Size import Agda.Utils.Pretty #include "undefined.h" import Agda.Utils.Impossible type Color = Term type ArgInfo = Common.ArgInfo Color type Arg a = Common.Arg Color a type Dom a = Common.Dom Color a type NamedArg a = Common.NamedArg Color a -- | Type of argument lists. -- type Args = [Arg Term] type NamedArgs = [NamedArg Term] -- | Store the names of the record fields in the constructor. -- This allows reduction of projection redexes outside of TCM. -- For instance, during substitution and application. data ConHead = ConHead { conName :: QName -- ^ The name of the constructor. , conInductive :: Induction -- ^ Record constructors can be coinductive. , conFields :: [QName] -- ^ The name of the record fields. -- Empty list for data constructors. -- 'Arg' is not needed here since it -- is stored in the constructor args. } deriving (Typeable) instance Eq ConHead where (==) = (==) `on` conName instance Ord ConHead where (<=) = (<=) `on` conName instance Show ConHead where show (ConHead c i fs) = show c ++ "(" ++ show i ++ ")" ++ show fs instance HasRange ConHead where getRange = getRange . conName instance SetRange ConHead where setRange r = mapConName (setRange r) class LensConName a where getConName :: a -> QName setConName :: QName -> a -> a setConName = mapConName . const mapConName :: (QName -> QName) -> a -> a mapConName f a = setConName (f (getConName a)) a instance LensConName ConHead where getConName = conName setConName c con = con { conName = c } -- | Raw values. -- -- @Def@ is used for both defined and undefined constants. -- Assume there is a type declaration and a definition for -- every constant, even if the definition is an empty -- list of clauses. -- data Term = Var {-# UNPACK #-} !Int Elims -- ^ @x es@ neutral | Lam ArgInfo (Abs Term) -- ^ Terms are beta normal. Relevance is ignored | ExtLam [Clause] Args -- ^ Only used by unquote --> reify. Should never appear elsewhere. | Lit Literal | Def QName Elims -- ^ @f es@, possibly a delta/iota-redex | Con ConHead Args -- ^ @c vs@ | Pi (Dom Type) (Abs Type) -- ^ dependent or non-dependent function space | Sort Sort | Level Level | MetaV {-# UNPACK #-} !MetaId Elims | DontCare Term -- ^ Irrelevant stuff in relevant position, but created -- in an irrelevant context. Basically, an internal -- version of the irrelevance axiom @.irrAx : .A -> A@. | Shared !(Ptr Term) -- ^ Explicit sharing deriving (Typeable, Show) -- | Eliminations, subsuming applications and projections. -- data Elim' a = Apply (Arg a) | Proj QName -- ^ name of a record projection deriving (Typeable, Show, Functor, Foldable, Traversable) type Elim = Elim' Term type Elims = [Elim] -- ^ eliminations ordered left-to-right. -- | Names in binders and arguments. type ArgName = String argNameToString :: ArgName -> String argNameToString = id stringToArgName :: String -> ArgName stringToArgName = id appendArgNames :: ArgName -> ArgName -> ArgName appendArgNames = (++) nameToArgName :: Name -> ArgName nameToArgName = stringToArgName . prettyShow -- | Binder. -- 'Abs': The bound variable might appear in the body. -- 'NoAbs' is pseudo-binder, it does not introduce a fresh variable, -- similar to the @const@ of Haskell. data Abs a = Abs { absName :: ArgName, unAbs :: a } -- ^ The body has (at least) one free variable. -- Danger: 'unAbs' doesn't shift variables properly | NoAbs { absName :: ArgName, unAbs :: a } deriving (Typeable, Functor, Foldable, Traversable) instance Decoration Abs where traverseF f (Abs x a) = Abs x <$> f a traverseF f (NoAbs x a) = NoAbs x <$> f a -- | Types are terms with a sort annotation. -- data Type' a = El { _getSort :: Sort, unEl :: a } deriving (Typeable, Show, Functor, Foldable, Traversable) type Type = Type' Term instance Decoration Type' where traverseF f (El s a) = El s <$> f a class LensSort a where lensSort :: Lens' Sort a getSort :: a -> Sort getSort a = a ^. lensSort instance LensSort (Type' a) where lensSort f (El s a) = f s <&> \ s' -> El s' a -- General instance leads to overlapping instances. -- instance (Decoration f, LensSort a) => LensSort (f a) where instance LensSort a => LensSort (Common.Dom c a) where lensSort = traverseF . lensSort instance LensSort a => LensSort (Abs a) where lensSort = traverseF . lensSort -- | Sequence of types. An argument of the first type is bound in later types -- and so on. data Tele a = EmptyTel | ExtendTel a (Abs (Tele a)) -- ^ 'Abs' is never 'NoAbs'. deriving (Typeable, Show, Functor, Foldable, Traversable) type Telescope = Tele (Dom Type) -- | A traversal for the names in a telescope. mapAbsNamesM :: Applicative m => (ArgName -> m ArgName) -> Tele a -> m (Tele a) mapAbsNamesM f EmptyTel = pure EmptyTel mapAbsNamesM f (ExtendTel a ( Abs x b)) = ExtendTel a <$> ( Abs <$> f x <*> mapAbsNamesM f b) mapAbsNamesM f (ExtendTel a (NoAbs x b)) = ExtendTel a <$> (NoAbs <$> f x <*> mapAbsNamesM f b) -- Ulf, 2013-11-06: Last case is really impossible but I'd rather find out we -- violated that invariant somewhere other than here. mapAbsNames :: (ArgName -> ArgName) -> Tele a -> Tele a mapAbsNames f = runIdentity . mapAbsNamesM (Identity . f) -- Ulf, 2013-11-06 -- The record parameter is named "" inside the record module so we can avoid -- printing it (issue 208), but we don't want that to show up in the type of -- the functions in the module (issue 892). This function is used on the record -- module telescope before adding it to a type in -- TypeChecking.Monad.Signature.addConstant (to handle functions defined in -- record modules) and TypeChecking.Rules.Record.checkProjection (to handle -- record projections). replaceEmptyName :: ArgName -> Tele a -> Tele a replaceEmptyName x = mapAbsNames $ \ y -> if null y then x else y -- | Sorts. -- data Sort = Type Level -- ^ @Set ℓ@. | Prop -- ^ Dummy sort. | Inf -- ^ @Setω@. | SizeUniv -- ^ @SizeUniv@, a sort inhabited by type @Size@. | DLub Sort (Abs Sort) -- ^ Dependent least upper bound. -- If the free variable occurs in the second sort, -- the whole thing should reduce to Inf, -- otherwise it's the normal lub. deriving (Typeable, Show) -- | A level is a maximum expression of 0..n 'PlusLevel' expressions -- each of which is a number or an atom plus a number. -- -- The empty maximum is the canonical representation for level 0. newtype Level = Max [PlusLevel] deriving (Show, Typeable) data PlusLevel = ClosedLevel Integer -- ^ @n@, to represent @Setₙ@. | Plus Integer LevelAtom -- ^ @n + ℓ@. deriving (Show, Typeable) -- | An atomic term of type @Level@. data LevelAtom = MetaLevel MetaId Elims -- ^ A meta variable targeting @Level@ under some eliminations. | BlockedLevel MetaId Term -- ^ A term of type @Level@ whose reduction is blocked by a meta. | NeutralLevel NotBlocked Term -- ^ A neutral term of type @Level@. | UnreducedLevel Term -- ^ Introduced by 'instantiate', removed by 'reduce'. deriving (Show, Typeable) -- | A meta variable identifier is just a natural number. -- newtype MetaId = MetaId { metaId :: Nat } deriving (Eq, Ord, Num, Real, Enum, Integral, Typeable) -- | Even if we are not stuck on a meta during reduction -- we can fail to reduce a definition by pattern matching -- for another reason. data NotBlocked = StuckOn Elim -- ^ The 'Elim' is neutral and blocks a pattern match. | Underapplied -- ^ Not enough arguments were supplied to complete the matching. | AbsurdMatch -- ^ We matched an absurd clause, results in a neutral 'Def'. | MissingClauses -- ^ We ran out of clauses, all considered clauses -- produced an actual mismatch. -- This can happen when try to reduce a function application -- but we are still missing some function clauses. -- See "Agda.TypeChecking.Patterns.Match". | ReallyNotBlocked -- ^ Reduction was not blocked, we reached a whnf -- which can be anything but a stuck @'Def'@. deriving (Show, Typeable) -- | 'ReallyNotBlocked' is the unit. -- 'MissingClauses' is dominant. -- @'StuckOn'{}@ should be propagated, if tied, we take the left. instance Monoid NotBlocked where -- ReallyNotBlocked is neutral mempty = ReallyNotBlocked ReallyNotBlocked `mappend` b = b -- MissingClauses is dominant (absorptive) b@MissingClauses `mappend` _ = b _ `mappend` b@MissingClauses = b -- StuckOn is second strongest b@StuckOn{} `mappend` _ = b _ `mappend` b@StuckOn{} = b b `mappend` _ = b -- | Something where a meta variable may block reduction. data Blocked t = Blocked { theBlockingMeta :: MetaId , ignoreBlocking :: t } | NotBlocked { blockingStatus :: NotBlocked, ignoreBlocking :: t } deriving (Typeable, Show, Functor, Foldable, Traversable) -- deriving (Typeable, Eq, Ord, Functor, Foldable, Traversable) -- | Blocking by a meta is dominant. instance Applicative Blocked where pure = notBlocked f <*> e = ((f $> ()) `mappend` (e $> ())) $> ignoreBlocking f (ignoreBlocking e) -- -- | Blocking by a meta is dominant. -- instance Applicative Blocked where -- pure = notBlocked -- Blocked x f <*> e = Blocked x $ f (ignoreBlocking e) -- NotBlocked nb f <*> Blocked x e = Blocked x $ f e -- NotBlocked nb f <*> NotBlocked nb' e = NotBlocked (nb `mappend` nb') $ f e -- | @'Blocked' t@ without the @t@. type Blocked_ = Blocked () instance Monoid Blocked_ where mempty = notBlocked () b@Blocked{} `mappend` _ = b _ `mappend` b@Blocked{} = b NotBlocked x _ `mappend` NotBlocked y _ = NotBlocked (x `mappend` y) () -- See Issue 1573. #if !MIN_VERSION_transformers(0,4,1) instance Error Blocked_ where noMsg = __IMPOSSIBLE__ #endif -- | When trying to reduce @f es@, on match failed on one -- elimination @e ∈ es@ that came with info @r :: NotBlocked@. -- @stuckOn e r@ produces the new @NotBlocked@ info. -- -- 'MissingClauses' must be propagated, as this is blockage -- that can be lifted in the future (as more clauses are added). -- -- @'StuckOn' e0@ is also propagated, since it provides more -- precise information as @StuckOn e@ (as @e0@ is the original -- reason why reduction got stuck and usually a subterm of @e@). -- An information like @StuckOn (Apply (Arg info (Var i [])))@ -- (stuck on a variable) could be used by the lhs/coverage checker -- to trigger a split on that (pattern) variable. -- -- In the remaining cases for @r@, we are terminally stuck -- due to @StuckOn e@. Propagating @'AbsurdMatch'@ does not -- seem useful. -- -- 'Underapplied' must not be propagated, as this would mean -- that @f es@ is underapplied, which is not the case (it is stuck). -- Note that 'Underapplied' can only arise when projection patterns were -- missing to complete the original match (in @e@). -- (Missing ordinary pattern would mean the @e@ is of function type, -- but we cannot match against something of function type.) stuckOn :: Elim -> NotBlocked -> NotBlocked stuckOn e r = case r of MissingClauses -> r StuckOn{} -> r Underapplied -> r' AbsurdMatch -> r' ReallyNotBlocked -> r' where r' = StuckOn e --------------------------------------------------------------------------- -- * Definitions --------------------------------------------------------------------------- -- | A clause is a list of patterns and the clause body should @Bind@. -- -- The telescope contains the types of the pattern variables and the -- permutation is how to get from the order the variables occur in -- the patterns to the order they occur in the telescope. The body -- binds the variables in the order they appear in the patterns. -- -- @clauseTel ~ permute clausePerm (patternVars namedClausePats)@ -- -- Terms in dot patterns are valid in the clause telescope. -- -- For the purpose of the permutation and the body dot patterns count -- as variables. TODO: Change this! data Clause = Clause { clauseRange :: Range , clauseTel :: Telescope -- ^ @Δ@: The types of the pattern variables. , clausePerm :: Permutation -- ^ @π@ with @Γ ⊢ renamingR π : Δ@, which means @Δ ⊢ renaming π : Γ@. , namedClausePats :: [NamedArg Pattern] -- ^ @let Γ = patternVars namedClausePats@ , clauseBody :: ClauseBody -- ^ @λΓ.v@ , clauseType :: Maybe (Arg Type) -- ^ @Δ ⊢ t@. The type of the rhs under @clauseTel@. -- Used, e.g., by @TermCheck@. -- Can be 'Irrelevant' if we encountered an irrelevant projection -- pattern on the lhs. } deriving (Typeable, Show) clausePats :: Clause -> [Arg Pattern] clausePats = map (fmap namedThing) . namedClausePats data ClauseBodyF a = Body a | Bind (Abs (ClauseBodyF a)) | NoBody -- ^ for absurd clauses. deriving (Typeable, Show, Functor, Foldable, Traversable) type ClauseBody = ClauseBodyF Term imapClauseBody :: (Nat -> a -> b) -> ClauseBodyF a -> ClauseBodyF b imapClauseBody f b = go 0 b where go i (Body x) = Body (f i x) go _ NoBody = NoBody go !i (Bind b) = Bind $ go (i + 1) <$> b instance HasRange Clause where getRange = clauseRange -- | Pattern variables. type PatVarName = ArgName patVarNameToString :: PatVarName -> String patVarNameToString = argNameToString nameToPatVarName :: Name -> PatVarName nameToPatVarName = nameToArgName -- | Patterns are variables, constructors, or wildcards. -- @QName@ is used in @ConP@ rather than @Name@ since -- a constructor might come from a particular namespace. -- This also meshes well with the fact that values (i.e. -- the arguments we are matching with) use @QName@. -- data Pattern' x = VarP x -- ^ @x@ | DotP Term -- ^ @.t@ | ConP ConHead ConPatternInfo [NamedArg (Pattern' x)] -- ^ @c ps@ -- The subpatterns do not contain any projection copatterns. | LitP Literal -- ^ E.g. @5@, @"hello"@. | ProjP QName -- ^ Projection copattern. Can only appear by itself. deriving (Typeable, Show, Functor, Foldable, Traversable) type Pattern = Pattern' PatVarName -- ^ The @PatVarName@ is a name suggestion. -- | Type used when numbering pattern variables. type DeBruijnPattern = Pattern' (Int, PatVarName) namedVarP :: PatVarName -> Named (Ranged PatVarName) Pattern namedVarP x = Named named $ VarP x where named = if isUnderscore x then Nothing else Just $ unranged x -- | The @ConPatternInfo@ states whether the constructor belongs to -- a record type (@Just@) or data type (@Nothing@). -- In the former case, the @Bool@ says whether the record pattern -- orginates from the expansion of an implicit pattern. -- The @Type@ is the type of the whole record pattern. -- The scope used for the type is given by any outer scope -- plus the clause's telescope ('clauseTel'). data ConPatternInfo = ConPatternInfo { conPRecord :: Maybe ConPOrigin -- ^ @Nothing@ if data constructor. -- @Just@ if record constructor. , conPType :: Maybe (Arg Type) -- ^ The type of the whole constructor pattern. -- Should be present (@Just@) if constructor pattern is -- is generated ordinarily by type-checking. -- Could be absent (@Nothing@) if pattern comes from some -- plugin (like Agsy). -- Needed e.g. for with-clause stripping. } deriving (Typeable, Show) noConPatternInfo :: ConPatternInfo noConPatternInfo = ConPatternInfo Nothing Nothing -- | Extract pattern variables in left-to-right order. -- A 'DotP' is also treated as variable (see docu for 'Clause'). patternVars :: Arg Pattern -> [Arg (Either PatVarName Term)] patternVars (Common.Arg i (VarP x) ) = [Common.Arg i $ Left x] patternVars (Common.Arg i (DotP t) ) = [Common.Arg i $ Right t] patternVars (Common.Arg i (ConP _ _ ps)) = List.concat $ map (patternVars . fmap namedThing) ps patternVars (Common.Arg i (LitP l) ) = [] patternVars (Common.Arg i ProjP{} ) = [] -- | Does the pattern perform a match that could fail? properlyMatching :: Pattern -> Bool properlyMatching VarP{} = False properlyMatching DotP{} = False properlyMatching LitP{} = True properlyMatching (ConP _ ci ps) = isNothing (conPRecord ci) || -- not a record cons List.any (properlyMatching . namedArg) ps -- or one of subpatterns is a proper m properlyMatching ProjP{} = True instance IsProjP Pattern where isProjP (ProjP d) = Just d isProjP _ = Nothing ----------------------------------------------------------------------------- -- * Explicit substitutions ----------------------------------------------------------------------------- -- | Substitutions. data Substitution = IdS -- ^ Identity substitution. -- @Γ ⊢ IdS : Γ@ | EmptyS -- ^ Empty substitution, lifts from the empty context. -- Apply this to closed terms you want to use in a non-empty context. -- @Γ ⊢ EmptyS : ()@ | Term :# Substitution -- ^ Substitution extension, ``cons''. -- @ -- Γ ⊢ u : Aρ Γ ⊢ ρ : Δ -- ---------------------- -- Γ ⊢ u :# ρ : Δ, A -- @ | Strengthen Empty Substitution -- ^ Strengthening substitution. First argument is @__IMPOSSIBLE__@. -- Apply this to a term which does not contain variable 0 -- to lower all de Bruijn indices by one. -- @ -- Γ ⊢ ρ : Δ -- --------------------------- -- Γ ⊢ Strengthen ρ : Δ, A -- @ | Wk !Int Substitution -- ^ Weakning substitution, lifts to an extended context. -- @ -- Γ ⊢ ρ : Δ -- ------------------- -- Γ, Ψ ⊢ Wk |Ψ| ρ : Δ -- @ | Lift !Int Substitution -- ^ Lifting substitution. Use this to go under a binder. -- @Lift 1 ρ == var 0 :# Wk 1 ρ@. -- @ -- Γ ⊢ ρ : Δ -- ------------------------- -- Γ, Ψρ ⊢ Lift |Ψ| ρ : Δ, Ψ -- @ deriving (Show) infixr 4 :# --------------------------------------------------------------------------- -- * Absurd Lambda --------------------------------------------------------------------------- -- | Absurd lambdas are internally represented as identity -- with variable name "()". absurdBody :: Abs Term absurdBody = Abs absurdPatternName $ Var 0 [] isAbsurdBody :: Abs Term -> Bool isAbsurdBody (Abs x (Var 0 [])) = isAbsurdPatternName x isAbsurdBody _ = False absurdPatternName :: PatVarName absurdPatternName = "()" isAbsurdPatternName :: PatVarName -> Bool isAbsurdPatternName x = x == absurdPatternName --------------------------------------------------------------------------- -- * Pointers and Sharing --------------------------------------------------------------------------- ignoreSharing :: Term -> Term -- ignoreSharing (Shared p) = ignoreSharing $ derefPtr p ignoreSharing v = v ignoreSharingType :: Type -> Type -- ignoreSharingType (El s v) = El s (ignoreSharing v) ignoreSharingType v = v -- | Introduce sharing. shared :: Term -> Term -- shared v@Shared{} = v -- shared v@(Var _ []) = v -- shared v = Shared (newPtr v) shared v = v sharedType :: Type -> Type -- sharedType (El s v) = El s (shared v) sharedType v = v -- | Typically m would be TCM and f would be Blocked. updateSharedFM :: (Monad m, Applicative m, Traversable f) => (Term -> m (f Term)) -> Term -> m (f Term) updateSharedFM f v0@(Shared p) = do fv <- f (derefPtr p) flip traverse fv $ \v -> case derefPtr (setPtr v p) of Var _ [] -> return v _ -> compressPointerChain v0 `pseq` return v0 updateSharedFM f v = f v updateSharedM :: Monad m => (Term -> m Term) -> Term -> m Term updateSharedM f v0@(Shared p) = do v <- f (derefPtr p) case derefPtr (setPtr v p) of Var _ [] -> return v _ -> compressPointerChain v0 `pseq` return v0 updateSharedM f v = f v updateShared :: (Term -> Term) -> Term -> Term updateShared f v0@(Shared p) = case derefPtr (setPtr (f $ derefPtr p) p) of v@(Var _ []) -> v _ -> compressPointerChain v0 `pseq` v0 updateShared f v = f v pointerChain :: Term -> [Ptr Term] pointerChain (Shared p) = p : pointerChain (derefPtr p) pointerChain _ = [] -- Redirect all top-level pointers to point to the last pointer. So, after -- compression there are at most two top-level indirections. compressPointerChain :: Term -> Term compressPointerChain v = case reverse $ pointerChain v of p:_:ps@(_:_) -> setPointers (Shared p) ps _ -> v where setPointers _ [] = v setPointers u (p : ps) = setPtr u p `seq` setPointers u ps --------------------------------------------------------------------------- -- * Smart constructors --------------------------------------------------------------------------- -- | An unapplied variable. var :: Nat -> Term var i | i >= 0 = Var i [] | otherwise = __IMPOSSIBLE__ -- | Add 'DontCare' is it is not already a @DontCare@. dontCare :: Term -> Term dontCare v = case ignoreSharing v of DontCare{} -> v _ -> DontCare v -- | A dummy type. typeDontCare :: Type typeDontCare = El Prop (Sort Prop) -- | Top sort (Set\omega). topSort :: Type topSort = El Inf (Sort Inf) sort :: Sort -> Type sort s = El (sSuc s) $ Sort s varSort :: Int -> Sort varSort n = Type $ Max [Plus 0 $ NeutralLevel mempty $ var n] -- | Get the next higher sort. sSuc :: Sort -> Sort sSuc Prop = mkType 1 sSuc Inf = Inf sSuc SizeUniv = SizeUniv sSuc (DLub a b) = DLub (sSuc a) (fmap sSuc b) sSuc (Type l) = Type $ levelSuc l levelSuc :: Level -> Level levelSuc (Max []) = Max [ClosedLevel 1] levelSuc (Max as) = Max $ map inc as where inc (ClosedLevel n) = ClosedLevel (n + 1) inc (Plus n l) = Plus (n + 1) l mkType :: Integer -> Sort mkType n = Type $ Max [ClosedLevel n | n > 0] impossibleTerm :: String -> Int -> Term impossibleTerm file line = Lit $ LitString noRange $ unlines [ "An internal error has occurred. Please report this as a bug." , "Location of the error: " ++ file ++ ":" ++ show line ] -- | Constructing a singleton telescope. class SgTel a where sgTel :: a -> Telescope instance SgTel (ArgName, Dom Type) where sgTel (x, dom) = ExtendTel dom $ Abs x EmptyTel instance SgTel (Dom (ArgName, Type)) where sgTel (Common.Dom ai (x, t)) = ExtendTel (Common.Dom ai t) $ Abs x EmptyTel instance SgTel (Dom Type) where sgTel dom = sgTel (stringToArgName "_", dom) hackReifyToMeta :: Term hackReifyToMeta = DontCare $ Lit $ LitInt noRange (-42) isHackReifyToMeta :: Term -> Bool isHackReifyToMeta (DontCare (Lit (LitInt r (-42)))) = r == noRange isHackReifyToMeta _ = False --------------------------------------------------------------------------- -- * Handling blocked terms. --------------------------------------------------------------------------- blockingMeta :: Blocked t -> Maybe MetaId blockingMeta (Blocked m _) = Just m blockingMeta NotBlocked{} = Nothing blocked :: MetaId -> a -> Blocked a blocked x = Blocked x notBlocked :: a -> Blocked a notBlocked = NotBlocked ReallyNotBlocked --------------------------------------------------------------------------- -- * Simple operations on terms and types. --------------------------------------------------------------------------- -- | Removing a topmost 'DontCare' constructor. stripDontCare :: Term -> Term stripDontCare v = case ignoreSharing v of DontCare v -> v _ -> v -- | Doesn't do any reduction. arity :: Type -> Nat arity t = case ignoreSharing $ unEl t of Pi _ b -> 1 + arity (unAbs b) _ -> 0 -- | Make a name that is not in scope. notInScopeName :: ArgName -> ArgName notInScopeName = stringToArgName . ("." ++) . argNameToString -- | Pick the better name suggestion, i.e., the one that is not just underscore. class Suggest a b where suggest :: a -> b -> String instance Suggest String String where suggest "_" y = y suggest x _ = x instance Suggest (Abs a) (Abs b) where suggest b1 b2 = suggest (absName b1) (absName b2) instance Suggest String (Abs b) where suggest x b = suggest x (absName b) instance Suggest Name (Abs b) where suggest n b = suggest (nameToArgName n) (absName b) --------------------------------------------------------------------------- -- * Eliminations. --------------------------------------------------------------------------- -- | Convert top-level postfix projections into prefix projections. unSpine :: Term -> Term unSpine v = case hasElims v of Just (h, es) -> unSpine' h [] es Nothing -> v where unSpine' :: (Elims -> Term) -> Elims -> Elims -> Term unSpine' h res es = case es of [] -> v e@(Apply a) : es' -> unSpine' h (e : res) es' Proj f : es' -> unSpine' (Def f) [Apply (defaultArg v)] es' where v = h $ reverse res -- | A view distinguishing the neutrals @Var@, @Def@, and @MetaV@ which -- can be projected. hasElims :: Term -> Maybe (Elims -> Term, Elims) hasElims v = case ignoreSharing v of Var i es -> Just (Var i, es) Def f es -> Just (Def f, es) MetaV x es -> Just (MetaV x, es) Con{} -> Nothing Lit{} -> Nothing Lam{} -> Nothing Pi{} -> Nothing Sort{} -> Nothing Level{} -> Nothing DontCare{} -> Nothing ExtLam{} -> Nothing Shared{} -> __IMPOSSIBLE__ {- PROBABLY USELESS getElims :: Term -> (Elims -> Term, Elims) getElims v = maybe default id $ hasElims v where default = (\ [] -> v, []) -} -- | Drop 'Apply' constructor. (Unsafe!) argFromElim :: Elim -> Arg Term argFromElim (Apply u) = u argFromElim Proj{} = __IMPOSSIBLE__ -- | Drop 'Apply' constructor. (Safe) isApplyElim :: Elim -> Maybe (Arg Term) isApplyElim (Apply u) = Just u isApplyElim Proj{} = Nothing -- | Drop 'Apply' constructors. (Safe) allApplyElims :: Elims -> Maybe Args allApplyElims = mapM isApplyElim -- | Split at first non-'Apply' splitApplyElims :: Elims -> (Args, Elims) splitApplyElims (Apply u : es) = (u :) *** id $ splitApplyElims es splitApplyElims es = ([], es) class IsProjElim e where isProjElim :: e -> Maybe QName instance IsProjElim Elim where isProjElim (Proj d) = Just d isProjElim Apply{} = Nothing -- | Discard @Proj f@ entries. dropProjElims :: IsProjElim e => [e] -> [e] dropProjElims = filter (isNothing . isProjElim) -- | Discards @Proj f@ entries. argsFromElims :: Elims -> Args argsFromElims = map argFromElim . dropProjElims {- NOTE: Elim' already contains Arg. -- | Commute functors 'Arg' and 'Elim\''. swapArgElim :: Common.Arg c (Elim' a) -> Elim' (Common.Arg c a) swapArgElim (Common.Arg ai (Apply a)) = Apply (Common.Arg ai a) swapArgElim (Common.Arg ai (Proj d)) = Proj d -- IMPOSSIBLE TO DEFINE swapElimArg :: Elim' (Common.Arg c a) -> Common.Arg c (Elim' a) swapElimArg (Apply (Common.Arg ai a)) = Common.Arg ai (Apply a) swapElimArg (Proj d) = defaultArg (Proj d) -} --------------------------------------------------------------------------- -- * Null instances. --------------------------------------------------------------------------- instance Null (Tele a) where empty = EmptyTel null EmptyTel = True null ExtendTel{} = False instance Null ClauseBody where empty = NoBody null NoBody = True null _ = False -- | A 'null' clause is one with no patterns and no rhs. -- Should not exist in practice. instance Null Clause where empty = Clause empty empty empty empty empty empty null (Clause r tel perm pats body t) = null tel && null pats && null body --------------------------------------------------------------------------- -- * Show instances. --------------------------------------------------------------------------- instance Show a => Show (Abs a) where showsPrec p (Abs x a) = showParen (p > 0) $ showString "Abs " . shows x . showString " " . showsPrec 10 a showsPrec p (NoAbs x a) = showParen (p > 0) $ showString "NoAbs " . shows x . showString " " . showsPrec 10 a -- | Show non-record version of this newtype. instance Show MetaId where showsPrec p (MetaId n) = showParen (p > 0) $ showString "MetaId " . shows n -- instance Show t => Show (Blocked t) where -- showsPrec p (Blocked m x) = showParen (p > 0) $ -- showString "Blocked " . shows m . showString " " . showsPrec 10 x -- showsPrec p (NotBlocked x) = showsPrec p x --------------------------------------------------------------------------- -- * Sized instances and TermSize. --------------------------------------------------------------------------- -- | The size of a telescope is its length (as a list). instance Sized (Tele a) where size EmptyTel = 0 size (ExtendTel _ tel) = 1 + size tel instance Sized a => Sized (Abs a) where size = size . unAbs -- | The size of a term is roughly the number of nodes in its -- syntax tree. This number need not be precise for logical -- correctness of Agda, it is only used for reporting -- (and maybe decisions regarding performance). -- -- Not counting towards the term size are: -- -- * sort and color annotations, -- * projections. -- class TermSize a where termSize :: a -> Int termSize = getSum . tsize tsize :: a -> Sum Int instance (Foldable t, TermSize a) => TermSize (t a) where tsize = foldMap tsize instance TermSize Term where tsize v = case v of Var _ vs -> 1 + tsize vs Def _ vs -> 1 + tsize vs Con _ vs -> 1 + tsize vs MetaV _ vs -> 1 + tsize vs Level l -> tsize l Lam _ f -> 1 + tsize f Lit _ -> 1 Pi a b -> 1 + tsize a + tsize b Sort s -> tsize s DontCare mv -> tsize mv Shared p -> tsize (derefPtr p) ExtLam{} -> __IMPOSSIBLE__ instance TermSize Sort where tsize s = case s of Type l -> 1 + tsize l Prop -> 1 Inf -> 1 SizeUniv -> 1 DLub s s' -> 1 + tsize s + tsize s' instance TermSize Level where tsize (Max as) = 1 + tsize as instance TermSize PlusLevel where tsize (ClosedLevel _) = 1 tsize (Plus _ a) = tsize a instance TermSize LevelAtom where tsize (MetaLevel _ vs) = 1 + tsize vs tsize (BlockedLevel _ v) = tsize v tsize (NeutralLevel _ v) = tsize v tsize (UnreducedLevel v) = tsize v instance TermSize Substitution where tsize IdS = 1 tsize EmptyS = 1 tsize (Wk _ rho) = 1 + tsize rho tsize (t :# rho) = 1 + tsize t + tsize rho tsize (Strengthen _ rho) = 1 + tsize rho tsize (Lift _ rho) = 1 + tsize rho --------------------------------------------------------------------------- -- * KillRange instances. --------------------------------------------------------------------------- instance KillRange ConHead where killRange (ConHead c i fs) = killRange3 ConHead c i fs instance KillRange Term where killRange v = case v of Var i vs -> killRange1 (Var i) vs Def c vs -> killRange2 Def c vs Con c vs -> killRange2 Con c vs MetaV m vs -> killRange1 (MetaV m) vs Lam i f -> killRange2 Lam i f Lit l -> killRange1 Lit l Level l -> killRange1 Level l Pi a b -> killRange2 Pi a b Sort s -> killRange1 Sort s DontCare mv -> killRange1 DontCare mv Shared p -> Shared $ updatePtr killRange p ExtLam c vs -> killRange2 ExtLam c vs instance KillRange Level where killRange (Max as) = killRange1 Max as instance KillRange PlusLevel where killRange l@ClosedLevel{} = l killRange (Plus n l) = killRange1 (Plus n) l instance KillRange LevelAtom where killRange (MetaLevel n as) = killRange1 (MetaLevel n) as killRange (BlockedLevel m v) = killRange1 (BlockedLevel m) v killRange (NeutralLevel r v) = killRange1 (NeutralLevel r) v killRange (UnreducedLevel v) = killRange1 UnreducedLevel v instance (KillRange a) => KillRange (Type' a) where killRange (El s v) = killRange2 El s v instance KillRange Sort where killRange s = case s of Prop -> Prop Inf -> Inf SizeUniv -> SizeUniv Type a -> killRange1 Type a DLub s1 s2 -> killRange2 DLub s1 s2 instance KillRange Substitution where killRange IdS = IdS killRange EmptyS = EmptyS killRange (Wk n rho) = killRange1 (Wk n) rho killRange (t :# rho) = killRange2 (:#) t rho killRange (Strengthen err rho) = killRange1 (Strengthen err) rho killRange (Lift n rho) = killRange1 (Lift n) rho instance KillRange ConPatternInfo where killRange (ConPatternInfo mr mt) = killRange1 (ConPatternInfo mr) mt instance KillRange Pattern where killRange p = case p of VarP{} -> p DotP v -> killRange1 DotP v ConP con info ps -> killRange3 ConP con info ps LitP l -> killRange1 LitP l ProjP q -> killRange1 ProjP q instance KillRange Clause where killRange (Clause r tel perm ps body t) = killRange6 Clause r tel perm ps body t instance KillRange a => KillRange (ClauseBodyF a) where killRange = fmap killRange instance KillRange a => KillRange (Tele a) where killRange = fmap killRange instance KillRange a => KillRange (Blocked a) where killRange = fmap killRange instance KillRange a => KillRange (Abs a) where killRange = fmap killRange instance KillRange a => KillRange (Elim' a) where killRange = fmap killRange --------------------------------------------------------------------------- -- * UniverseBi instances. --------------------------------------------------------------------------- instanceUniverseBiT' [] [t| (([Type], [Clause]), Pattern) |] instanceUniverseBiT' [] [t| (Args, Pattern) |] instanceUniverseBiT' [] [t| (Elims, Pattern) |] -- ? instanceUniverseBiT' [] [t| (([Type], [Clause]), Term) |] instanceUniverseBiT' [] [t| (Args, Term) |] instanceUniverseBiT' [] [t| (Elims, Term) |] -- ? instanceUniverseBiT' [] [t| ([Term], Term) |] ----------------------------------------------------------------------------- -- * Simple pretty printing ----------------------------------------------------------------------------- instance Pretty MetaId where pretty (MetaId n) = text $ "_" ++ show n instance Pretty Substitution where prettyPrec p rho = brackets $ pr rho where pr rho = case rho of IdS -> text "idS" EmptyS -> text "ε" t :# rho -> prettyPrec 1 t <+> text ":#" <+> pr rho Strengthen _ rho -> text "↓" <+> pr rho Wk n rho -> text ("↑" ++ show n) <+> pr rho Lift n rho -> text ("⇑" ++ show n) <+> pr rho instance Pretty Term where prettyPrec p v = case ignoreSharing v of Var x els -> text ("@" ++ show x) `pApp` els Lam _ b -> mparens (p > 0) $ sep [ text ("λ " ++ show (absName b) ++ " ->") , nest 2 $ pretty (unAbs b) ] Lit l -> pretty l Def q els -> text (show q) `pApp` els Con c vs -> text (show $ conName c) `pApp` map Apply vs Pi a (NoAbs _ b) -> mparens (p > 0) $ sep [ prettyPrec 1 (unDom a) <+> text "->" , nest 2 $ pretty b ] Pi a b -> mparens (p > 0) $ sep [ pDom (domInfo a) (text (absName b) <+> text ":" <+> pretty (unDom a)) <+> text "->" , nest 2 $ pretty (unAbs b) ] Sort s -> pretty s Level l -> pretty l MetaV x els -> pretty x `pApp` els DontCare v -> pretty v Shared{} -> __IMPOSSIBLE__ ExtLam{} -> __IMPOSSIBLE__ where pApp d els = mparens (not (null els) && p > 9) $ d <+> fsep (map (prettyPrec 10) els) pDom i = case getHiding i of NotHidden -> parens Hidden -> braces Instance -> braces . braces instance Pretty Level where prettyPrec p (Max as) = case as of [] -> prettyPrec p (ClosedLevel 0) [a] -> prettyPrec p a _ -> mparens (p > 9) $ List.foldr1 (\a b -> text "lub" <+> a <+> b) $ map (prettyPrec 10) as instance Pretty PlusLevel where prettyPrec p l = case l of ClosedLevel n -> sucs p n $ \_ -> text "lzero" Plus n a -> sucs p n $ \p -> prettyPrec p a where sucs p 0 d = d p sucs p n d = mparens (p > 9) $ text "lsuc" <+> sucs 10 (n - 1) d instance Pretty LevelAtom where prettyPrec p a = case a of MetaLevel x els -> prettyPrec p (MetaV x els) BlockedLevel _ v -> prettyPrec p v NeutralLevel _ v -> prettyPrec p v UnreducedLevel v -> prettyPrec p v instance Pretty Sort where prettyPrec p s = case s of Type (Max []) -> text "Set" Type (Max [ClosedLevel n]) -> text $ "Set" ++ show n Type l -> mparens (p > 9) $ text "Set" <+> prettyPrec 10 l Prop -> text "Prop" Inf -> text "Setω" SizeUniv -> text "SizeUniv" DLub s b -> mparens (p > 9) $ text "dlub" <+> prettyPrec 10 s <+> parens (sep [ text ("λ " ++ show (absName b) ++ " ->") , nest 2 $ pretty (unAbs b) ]) instance Pretty Type where prettyPrec p (El _ a) = prettyPrec p a instance Pretty Elim where prettyPrec p (Apply v) = prettyPrec p v prettyPrec _ (Proj x) = text ("." ++ show x) instance Pretty a => Pretty (Arg a) where prettyPrec p a = ($ unArg a) $ case getHiding a of NotHidden -> prettyPrec p Hidden -> braces . pretty Instance -> braces . braces . pretty