1{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, DeriveFunctor #-}
3{-| TT is the core language of Idris. The language has:
7 * A hierarchy of universes, with cumulativity: Type : Type1, Type1 : Type2, ...
9 * Pattern matching letrec binding
11 * (primitive types defined externally)
15 * Typechecker is kept as simple as possible - no unification, just a checker for incomplete terms.
17 * We have a simple collection of tactics which we use to elaborate source
18 programs with implicit syntax into fully explicit terms.
21module Idris.Core.TT(module Idris.Core.TT, module Idris.Core.TC) where
25import Control.Monad.State.Strict
26import Control.Monad.Trans.Error (Error(..))
28import qualified Data.Map.Strict as Map
30import qualified Data.Text as T
32import Data.Vector.Unboxed (Vector)
33import qualified Data.Vector.Unboxed as V
34import qualified Data.Binary as B
35import Data.Binary hiding (get, put)
36import Foreign.Storable (sizeOf)
38import Util.Pretty hiding (Str)
40data Option = TTypeInTType
44-- | Source location. These are typically produced by the parser 'Idris.Parser.getFC'
45data FC = FC { fc_fname :: String, -- ^ Filename
46 fc_line :: Int, -- ^ Line number
47 fc_column :: Int -- ^ Column number
50-- | Ignore source location equality (so deriving classes do not compare FCs)
55newtype FC' = FC' { unwrapFC :: FC }
58 FC' fc == FC' fc' = fcEq fc fc'
59 where fcEq (FC n l c) (FC n' l' c') = n == n' && l == l' && c == c'
61-- | Empty source location
65-- | Source location with file only
70deriving instance Binary FC
71deriving instance NFData FC
74instance Sized FC where
75 size (FC f l c) = 1 + length f
78 show (FC f l c) = f ++ ":" ++ show l ++ ":" ++ show c
80-- | Used for error reflection
81data ErrorReportPart = TextPart String
84 | SubReport [ErrorReportPart]
88-- Please remember to keep Err synchronised with
89-- Language.Reflection.Errors.Err in the stdlib!
91-- | Idris errors. Used as exceptions in the compiler, but reported to users
92-- if they reach the top level.
96 | CantUnify Bool t t (Err' t) [(Name, t)] Int
97 -- Int is 'score' - how much we did unify
98 -- Bool indicates recoverability, True indicates more info may make
99 -- unification succeed
100 | InfiniteUnify Name t [(Name, t)]
101 | CantConvert t t [(Name, t)]
102 | CantSolveGoal t [(Name, t)]
103 | UnifyScope Name Name t [(Name, t)]
104 | CantInferType String
105 | NonFunctionType t t
107 | TooManyArguments Name
109 | NoSuchVariable Name
113 | CantResolveAlts [String]
118 | NonCollapsiblePostulate Name
119 | AlreadyDefined Name
120 | ProofSearchFail (Err' t)
123 | Elaborating String Name (Err' t)
124 | ProviderError String
125 | LoadingFailed String (Err' t)
126 | ReflectionError [[ErrorReportPart]] (Err' t)
127 | ReflectionFailed String (Err' t)
128 deriving (Eq, Functor)
133deriving instance NFData Err
136instance Sized Err where
137 size (Msg msg) = length msg
138 size (InternalMsg msg) = length msg
139 size (CantUnify _ left right err _ score) = size left + size right + size err
140 size (InfiniteUnify _ right _) = size right
141 size (CantConvert left right _) = size left + size right
142 size (UnifyScope _ _ right _) = size right
143 size (NoSuchVariable name) = size name
144 size (NoTypeDecl name) = size name
145 size (NotInjective l c r) = size l + size c + size r
146 size (CantResolve trm) = size trm
147 size (NoRewriting trm) = size trm
148 size (CantResolveAlts _) = 1
149 size (IncompleteTerm trm) = size trm
150 size UniverseError = 1
151 size ProgramLineComment = 1
152 size (At fc err) = size fc + size err
153 size (Elaborating _ n err) = size err
154 size (ProviderError msg) = length msg
155 size (LoadingFailed fn e) = 1 + length fn + size e
159score (CantUnify _ _ _ m _ s) = s + score m
160score (CantResolve _) = 20
161score (NoSuchVariable _) = 1000
162score (ProofSearchFail _) = 10000
163score (CantSolveGoal _ _) = 10000
164score (InternalMsg _) = -1
167instance Show Err where
169 show (InternalMsg s) = "Internal error: " ++ show s
170 show (CantUnify _ l r e sc i) = "CantUnify " ++ show l ++ " " ++ show r ++ " "
171 ++ show e ++ " in " ++ show sc ++ " " ++ show i
172 show (CantSolveGoal g _) = "CantSolve " ++ show g
173 show (Inaccessible n) = show n ++ " is not an accessible pattern variable"
174 show (ProviderError msg) = "Type provider error: " ++ msg
175 show (LoadingFailed fn e) = "Loading " ++ fn ++ " failed: (TT) " ++ show e
176 show ProgramLineComment = "Program line next to comment"
177 show (At f e) = show f ++ ":" ++ show e
180instance Pretty Err where
181 pretty (Msg m) = text m
182 pretty (CantUnify _ l r e _ i) =
183 if size l + size r > breakingSize then
184 text "Cannot unify" <+> colon $$
185 nest nestingSize (pretty l <+> text "and" <+> pretty r) $$
186 nest nestingSize (text "where" <+> pretty e <+> text "with" <+> (text . show $ i))
188 text "Cannot unify" <+> colon <+> pretty l <+> text "and" <+> pretty r $$
189 nest nestingSize (text "where" <+> pretty e <+> text "with" <+> (text . show $ i))
190 pretty (ProviderError msg) = text msg
191 pretty err@(LoadingFailed _ _) = text (show err)
192 pretty _ = text "Error"
194instance Error Err where
199instance (Pretty a) => Pretty (TC a) where
200 pretty (OK ok) = pretty ok
202 if size err > breakingSize then
203 text "Error" <+> colon $$ (nest nestingSize $ pretty err)
205 text "Error" <+> colon <+> pretty err
207instance Show a => Show (TC a) where
209 show (Error str) = "Error: " ++ show str
214failMsg :: String -> TC a
215failMsg str = Error (Msg str)
217trun :: FC -> TC a -> TC a
219trun fc (Error e) = Error (At fc e)
221discard :: Monad m => m a -> m ()
222discard f = f >> return ()
224showSep :: String -> [String] -> String
227showSep sep (x:xs) = x ++ sep ++ showSep sep xs
229pmap f (x, y) = (f x, f y)
231traceWhen True msg a = trace msg a
232traceWhen False _ a = a
234-- RAW TERMS ----------------------------------------------------------------
236-- | Names are hierarchies of strings, describing scope (so no danger of
237-- duplicate names, but need to be careful on lookup).
238data Name = UN T.Text -- ^ User-provided name
239 | NS Name [T.Text] -- ^ Root, namespaces
240 | MN Int T.Text -- ^ Machine chosen names
241 | NErased -- ^ Name of somethng which is never used in scope
242 | SN SpecialName -- ^ Decorated function names
243 | SymRef Int -- ^ Reference to IBC file symbol table (used during serialisation)
246txt :: String -> T.Text
249str :: T.Text -> String
252tnull :: T.Text -> Bool
255thead :: T.Text -> Char
258-- Smart constructors for names, using old String style
262sNS :: Name -> [String] -> Name
263sNS n ss = NS n (map txt ss)
265sMN :: Int -> String -> Name
266sMN i s = MN i (txt s)
269deriving instance Binary Name
270deriving instance NFData Name
273data SpecialName = WhereN Int Name Name
274 | InstanceN Name [T.Text]
275 | ParentN Name T.Text
281deriving instance Binary SpecialName
282deriving instance NFData SpecialName
285sInstanceN :: Name -> [String] -> SpecialName
286sInstanceN n ss = InstanceN n (map T.pack ss)
288sParentN :: Name -> String -> SpecialName
289sParentN n s = ParentN n (T.pack s)
291instance Sized Name where
293 size (NS n els) = 1 + length els
297instance Pretty Name where
298 pretty (UN n) = text (T.unpack n)
299 pretty (NS n s) = pretty n
300 pretty (MN i s) = lbrace <+> text (T.unpack s) <+> (text . show $ i) <+> rbrace
301 pretty (SN s) = text (show s)
303instance Show Name where
305 show (NS n s) = showSep "." (map T.unpack (reverse s)) ++ "." ++ show n
306 show (MN _ u) | u == txt "underscore" = "_"
307 show (MN i s) = "{" ++ str s ++ show i ++ "}"
311instance Show SpecialName where
312 show (WhereN i p c) = show p ++ ", " ++ show c
313 show (InstanceN cl inst) = showSep ", " (map T.unpack inst) ++ " instance of " ++ show cl
314 show (MethodN m) = "method " ++ show m
315 show (ParentN p c) = show p ++ "#" ++ T.unpack c
316 show (CaseN n) = "case block in " ++ show n
317 show (ElimN n) = "<<" ++ show n ++ " eliminator>>"
319-- Show a name in a way decorated for code generation, not human reading
320showCG :: Name -> String
321showCG (UN n) = T.unpack n
322showCG (NS n s) = showSep "." (map T.unpack (reverse s)) ++ "." ++ showCG n
323showCG (MN _ u) | u == txt "underscore" = "_"
324showCG (MN i s) = "{" ++ T.unpack s ++ show i ++ "}"
325showCG (SN s) = showCG' s
326 where showCG' (WhereN i p c) = showCG p ++ ":" ++ showCG c ++ ":" ++ show i
327 showCG' (InstanceN cl inst) = '@':showCG cl ++ '$':showSep ":" (map T.unpack inst)
328 showCG' (MethodN m) = '!':showCG m
329 showCG' (ParentN p c) = showCG p ++ "#" ++ show c
330 showCG' (CaseN c) = showCG c ++ "_case"
331 showCG' (ElimN sn) = showCG sn ++ "_elim"
335-- |Contexts allow us to map names to things. A root name maps to a collection
336-- of things in different namespaces with that name.
337type Ctxt a = Map.Map Name (Map.Map Name a)
338emptyContext = Map.empty
340mapCtxt :: (a -> b) -> Ctxt a -> Ctxt b
343-- |Return True if the argument 'Name' should be interpreted as the name of a
345tcname (UN xs) | T.null xs = False
346 | otherwise = T.head xs == '@'
347tcname (NS n _) = tcname n
348tcname (SN (InstanceN _ _)) = True
349tcname (SN (MethodN _)) = True
350tcname (SN (ParentN _ _)) = True
353implicitable (NS n _) = implicitable n
354implicitable (UN xs) | T.null xs = False
355 | otherwise = isLower (T.head xs)
356implicitable (MN _ _) = True
357implicitable _ = False
362addDef :: Name -> a -> Ctxt a -> Ctxt a
363addDef n v ctxt = case Map.lookup (nsroot n) ctxt of
364 Nothing -> Map.insert (nsroot n)
365 (Map.insert n v Map.empty) ctxt
366 Just xs -> Map.insert (nsroot n)
367 (Map.insert n v xs) ctxt
369{-| Look up a name in the context, given an optional namespace.
370 The name (n) may itself have a (partial) namespace given.
372 Rules for resolution:
374 - if an explicit namespace is given, return the names which match it. If none
375 match, return all names.
377 - if the name has has explicit namespace given, return the names which match it
378 and ignore the given namespace.
380 - otherwise, return all names.
384lookupCtxtName :: Name -> Ctxt a -> [(Name, a)]
385lookupCtxtName n ctxt = case Map.lookup (nsroot n) ctxt of
386 Just xs -> filterNS (Map.toList xs)
390 filterNS ((found, v) : xs)
391 | nsmatch n found = (found, v) : filterNS xs
392 | otherwise = filterNS xs
394 nsmatch (NS n ns) (NS p ps) = ns `isPrefixOf` ps
395 nsmatch (NS _ _) _ = False
396 nsmatch looking found = True
398lookupCtxt :: Name -> Ctxt a -> [a]
399lookupCtxt n ctxt = map snd (lookupCtxtName n ctxt)
401lookupCtxtExact :: Name -> Ctxt a -> [a]
402lookupCtxtExact n ctxt = [ v | (nm, v) <- lookupCtxtName n ctxt, nm == n]
404updateDef :: Name -> (a -> a) -> Ctxt a -> Ctxt a
406 = let ds = lookupCtxtName n ctxt in
407 foldr (\ (n, t) c -> addDef n (f t) c) ctxt ds
409toAlist :: Ctxt a -> [(Name, a)]
410toAlist ctxt = let allns = map snd (Map.toList ctxt) in
411 concat (map (Map.toList) allns)
413addAlist :: Show a => [(Name, a)] -> Ctxt a -> Ctxt a
414addAlist [] ctxt = ctxt
415addAlist ((n, tm) : ds) ctxt = addDef n tm (addAlist ds ctxt)
417data NativeTy = IT8 | IT16 | IT32 | IT64
418 deriving (Show, Eq, Ord, Enum)
420instance Pretty NativeTy where
421 pretty IT8 = text "Bits8"
422 pretty IT16 = text "Bits16"
423 pretty IT32 = text "Bits32"
424 pretty IT64 = text "Bits64"
426data IntTy = ITFixed NativeTy | ITNative | ITBig | ITChar
428 deriving (Show, Eq, Ord)
430data ArithTy = ATInt IntTy | ATFloat -- TODO: Float vectors
431 deriving (Show, Eq, Ord)
433deriving instance NFData IntTy
434deriving instance NFData NativeTy
435deriving instance NFData ArithTy
438instance Pretty ArithTy where
439 pretty (ATInt ITNative) = text "Int"
440 pretty (ATInt ITBig) = text "BigInt"
441 pretty (ATInt ITChar) = text "Char"
442 pretty (ATInt (ITFixed n)) = pretty n
443 pretty (ATInt (ITVec e c)) = pretty e <> text "x" <> (text . show $ c)
444 pretty ATFloat = text "Float"
446nativeTyWidth :: NativeTy -> Int
448nativeTyWidth IT16 = 16
449nativeTyWidth IT32 = 32
450nativeTyWidth IT64 = 64
452{-# DEPRECATED intTyWidth "Non-total function, use nativeTyWidth and appropriate casing" #-}
453intTyWidth :: IntTy -> Int
454intTyWidth (ITFixed n) = nativeTyWidth n
455intTyWidth ITNative = 8 * sizeOf (0 :: Int)
456intTyWidth ITChar = error "IRTS.Lang.intTyWidth: Characters have platform and backend dependent width"
457intTyWidth ITBig = error "IRTS.Lang.intTyWidth: Big integers have variable width"
459data Const = I Int | BI Integer | Fl Double | Ch Char | Str String
460 | B8 Word8 | B16 Word16 | B32 Word32 | B64 Word64
461 | B8V (Vector Word8) | B16V (Vector Word16)
462 | B32V (Vector Word32) | B64V (Vector Word64)
463 | AType ArithTy | StrType
464 | PtrType | VoidType | Forgot
467deriving instance Binary Const
468deriving instance NFData Const
471instance Sized Const where
474instance Pretty Const where
475 pretty (I i) = text . show $ i
476 pretty (BI i) = text . show $ i
477 pretty (Fl f) = text . show $ f
478 pretty (Ch c) = text . show $ c
479 pretty (Str s) = text s
480 pretty (AType a) = pretty a
481 pretty StrType = text "String"
482 pretty PtrType = text "Ptr"
483 pretty VoidType = text "Void"
484 pretty Forgot = text "Forgot"
485 pretty (B8 w) = text . show $ w
486 pretty (B16 w) = text . show $ w
487 pretty (B32 w) = text . show $ w
488 pretty (B64 w) = text . show $ w
491 | RBind Name (Binder Raw) Raw
498instance Sized Raw where
500 size (RBind name bind right) = 1 + size bind + size right
501 size (RApp left right) = 1 + size left + size right
503 size (RForce raw) = 1 + size raw
504 size (RConstant const) = size const
506instance Pretty Raw where
510deriving instance Binary Raw
511deriving instance NFData Raw
514-- The type parameter `b` will normally be something like `TT Name` or just
515-- `Raw`. We do not make a type-level distinction between TT terms that happen
516-- to be TT types and TT terms that are not TT types.
517-- | All binding forms are represented in a uniform fashion. This type only represents
518-- the types of bindings (and their values, if any); the attached identifiers are part
519-- of the 'Bind' constructor for the 'TT' type.
520data Binder b = Lam { binderTy :: !b {-^ type annotation for bound variable-}}
521 | Pi { binderTy :: !b }
522 {-^ A binding that occurs in a function type expression, e.g. @(x:Int) -> ...@ -}
523 | Let { binderTy :: !b,
524 binderVal :: b {-^ value for bound variable-}}
525 -- ^ A binding that occurs in a @let@ expression
526 | NLet { binderTy :: !b,
528 | Hole { binderTy :: !b}
529 | GHole { envlen :: Int,
531 | Guess { binderTy :: !b,
533 | PVar { binderTy :: !b }
534 -- ^ A pattern variable
535 | PVTy { binderTy :: !b }
536 deriving (Show, Eq, Ord, Functor)
538deriving instance Binary Binder
539deriving instance NFData Binder
542instance Sized a => Sized (Binder a) where
543 size (Lam ty) = 1 + size ty
544 size (Pi ty) = 1 + size ty
545 size (Let ty val) = 1 + size ty + size val
546 size (NLet ty val) = 1 + size ty + size val
547 size (Hole ty) = 1 + size ty
548 size (GHole _ ty) = 1 + size ty
549 size (Guess ty val) = 1 + size ty + size val
550 size (PVar ty) = 1 + size ty
551 size (PVTy ty) = 1 + size ty
553fmapMB :: Monad m => (a -> m b) -> Binder a -> m (Binder b)
554fmapMB f (Let t v) = liftM2 Let (f t) (f v)
555fmapMB f (NLet t v) = liftM2 NLet (f t) (f v)
556fmapMB f (Guess t v) = liftM2 Guess (f t) (f v)
557fmapMB f (Lam t) = liftM Lam (f t)
558fmapMB f (Pi t) = liftM Pi (f t)
559fmapMB f (Hole t) = liftM Hole (f t)
560fmapMB f (GHole i t) = liftM (GHole i) (f t)
561fmapMB f (PVar t) = liftM PVar (f t)
562fmapMB f (PVTy t) = liftM PVTy (f t)
564raw_apply :: Raw -> [Raw] -> Raw
566raw_apply f (a : as) = raw_apply (RApp f a) as
568raw_unapply :: Raw -> (Raw, [Raw])
569raw_unapply t = ua [] t where
570 ua args (RApp f a) = ua (a:args) f
571 ua args t = (t, args)
573-- WELL TYPED TERMS ---------------------------------------------------------
575-- | Universe expressions for universe checking
576data UExp = UVar Int -- ^ universe variable
577 | UVal Int -- ^ explicit universe level
580deriving instance NFData UExp
583instance Sized UExp where
586-- We assume that universe levels have been checked, so anything external
587-- can just have the same universe variable and we won't get any new
590instance Binary UExp where
592 get = return (UVar (-1))
594instance Show UExp where
595 show (UVar x) | x < 26 = [toEnum (x + fromEnum 'a')]
596 | otherwise = toEnum ((x `mod` 26) + fromEnum 'a') : show (x `div` 26)
597 show (UVal x) = show x
598-- show (UMax l r) = "max(" ++ show l ++ ", " ++ show r ++")"
600-- | Universe constraints
601data UConstraint = ULT UExp UExp -- ^ Strictly less than
602 | ULE UExp UExp -- ^ Less than or equal to
605instance Show UConstraint where
606 show (ULT x y) = show x ++ " < " ++ show y
607 show (ULE x y) = show x ++ " <= " ++ show y
609type UCs = (Int, [UConstraint])
613 | DCon {nt_tag :: Int, nt_arity :: Int} -- ^ Data constructor
614 | TCon {nt_tag :: Int, nt_arity :: Int} -- ^ Type constructor
617deriving instance Binary NameType
618deriving instance NFData NameType
621instance Sized NameType where
624instance Pretty NameType where
627instance Eq NameType where
628 Bound == Bound = True
630 DCon _ a == DCon _ b = (a == b) -- ignore tag
631 TCon _ a == TCon _ b = (a == b) -- ignore tag
634-- | Terms in the core language. The type parameter is the type of
635-- identifiers used for bindings and explicit named references;
636-- usually we use @TT 'Name'@.
637data TT n = P NameType n (TT n) -- ^ named references with type
638 -- (P for "Parameter", motivated by McKinna and Pollack's
639 -- Pure Type Systems Formalized)
640 | V !Int -- ^ a resolved de Bruijn-indexed variable
641 | Bind n !(Binder (TT n)) (TT n) -- ^ a binding
642 | App !(TT n) (TT n) -- ^ function, function type, arg
643 | Constant Const -- ^ constant
644 | Proj (TT n) !Int -- ^ argument projection; runtime only
645 -- (-1) is a special case for 'subtract one from BI'
646 | Erased -- ^ an erased term
647 | Impossible -- ^ special case for totality checking
648 | TType UExp -- ^ the type of types at some level
649 deriving (Ord, Functor)
651deriving instance Binary TT
652deriving instance NFData TT
655class TermSize a where
656 termsize :: Name -> a -> Int
658instance TermSize a => TermSize [a] where
660 termsize n (x : xs) = termsize n x + termsize n xs
662instance TermSize (TT Name) where
663 termsize n (P _ n' _)
664 | n' == n = 1000000 -- recursive => really big
667 -- for `Bind` terms, we can erroneously declare a term
668 -- "recursive => really big" if the name of the bound
669 -- variable is the same as the name we're using
670 -- So generate a different name in that case.
671 termsize n (Bind n' (Let t v) sc)
672 = let rn = if n == n' then sMN 0 "noname" else n in
673 termsize rn v + termsize rn sc
674 termsize n (Bind n' b sc)
675 = let rn = if n == n' then sMN 0 "noname" else n in
677 termsize n (App f a) = termsize n f + termsize n a
678 termsize n (Proj t i) = termsize n t
681instance Sized a => Sized (TT a) where
682 size (P name n trm) = 1 + size name + size n + size trm
684 size (Bind nm binder bdy) = 1 + size nm + size binder + size bdy
685 size (App l r) = 1 + size l + size r
686 size (Constant c) = size c
688 size (TType u) = 1 + size u
690instance Pretty a => Pretty (TT a) where
691 pretty _ = text "test"
693type EnvTT n = [(n, Binder (TT n))]
695data Datatype n = Data { d_typename :: n,
698 d_cons :: [(n, TT n)] }
699 deriving (Show, Functor, Eq)
701instance Eq n => Eq (TT n) where
702 (==) (P xt x _) (P yt y _) = x == y
703 (==) (V x) (V y) = x == y
704 (==) (Bind _ xb xs) (Bind _ yb ys) = xs == ys && xb == yb
705 (==) (App fx ax) (App fy ay) = ax == ay && fx == fy
706 (==) (TType _) (TType _) = True -- deal with constraints later
707 (==) (Constant x) (Constant y) = x == y
708 (==) (Proj x i) (Proj y j) = x == y && i == j
713-- * A few handy operations on well typed terms:
715-- | A term is injective iff it is a data constructor, type constructor,
716-- constant, the type Type, pi-binding, or an application of an injective
718isInjective :: TT n -> Bool
719isInjective (P (DCon _ _) _ _) = True
720isInjective (P (TCon _ _) _ _) = True
721isInjective (Constant _) = True
722isInjective (TType x) = True
723isInjective (Bind _ (Pi _) sc) = True
724isInjective (App f a) = isInjective f
727-- | Count the number of instances of a de Bruijn index in a term
728vinstances :: Int -> TT n -> Int
729vinstances i (V x) | i == x = 1
730vinstances i (App f a) = vinstances i f + vinstances i a
731vinstances i (Bind x b sc) = instancesB b + vinstances (i + 1) sc
732 where instancesB (Let t v) = vinstances i v
736-- | Replace the outermost (index 0) de Bruijn variable with the given term
737instantiate :: TT n -> TT n -> TT n
738instantiate e = subst 0 where
739 subst i (V x) | i == x = e
740 subst i (Bind x b sc) = Bind x (fmap (subst i) b) (subst (i+1) sc)
741 subst i (App f a) = App (subst i f) (subst i a)
742 subst i (Proj x idx) = Proj (subst i x) idx
745-- | As 'instantiate', but also decrement the indices of all de Bruijn variables
746-- remaining in the term, so that there are no more references to the variable
747-- that has been substituted.
748substV :: TT n -> TT n -> TT n
749substV x tm = dropV 0 (instantiate x tm) where
750 dropV i (V x) | x > i = V (x - 1)
752 dropV i (Bind x b sc) = Bind x (fmap (dropV i) b) (dropV (i+1) sc)
753 dropV i (App f a) = App (dropV i f) (dropV i a)
754 dropV i (Proj x idx) = Proj (dropV i x) idx
757-- | Replace all non-free de Bruijn references in the given term with references
758-- to the name of their binding.
759explicitNames :: TT n -> TT n
760explicitNames (Bind x b sc) = let b' = fmap explicitNames b in
762 (explicitNames (instantiate
763 (P Bound x (binderTy b')) sc))
764explicitNames (App f a) = App (explicitNames f) (explicitNames a)
765explicitNames (Proj x idx) = Proj (explicitNames x) idx
768-- | Replace references to the given 'Name'-like id with references to
770pToV :: Eq n => n -> TT n -> TT n
772pToV' n i (P _ x _) | n == x = V i
773pToV' n i (Bind x b sc)
774-- We can assume the inner scope has been pToVed already, so continue to
775-- resolve names from the *outer* scope which may happen to have the same id.
776 | n == x = Bind x (fmap (pToV' n i) b) sc
777 | otherwise = Bind x (fmap (pToV' n i) b) (pToV' n (i+1) sc)
778pToV' n i (App f a) = App (pToV' n i f) (pToV' n i a)
779pToV' n i (Proj t idx) = Proj (pToV' n i t) idx
782-- increase de Bruijn indices, as if a binder has been added
783addBinder :: TT n -> TT n
786 ab top (V i) | i >= top = V (i + 1)
788 ab top (Bind x b sc) = Bind x (fmap (ab top) b) (ab (top + 1) sc)
789 ab top (App f a) = App (ab top f) (ab top a)
790 ab top (Proj t idx) = Proj (ab top t) idx
793-- | Convert several names. First in the list comes out as V 0
794pToVs :: Eq n => [n] -> TT n -> TT n
795pToVs ns tm = pToVs' ns tm 0 where
797 pToVs' (n:ns) tm i = pToV' n i (pToVs' ns tm (i+1))
799-- | Replace de Bruijn indices in the given term with explicit references to
800-- the names of the bindings they refer to. It is an error if the given term
801-- contains free de Bruijn indices.
804 vToP' env (V i) = let (n, b) = (env !! i) in
805 P Bound n (binderTy b)
806 vToP' env (Bind n b sc) = let b' = fmap (vToP' env) b in
807 Bind n b' (vToP' ((n, b'):env) sc)
808 vToP' env (App f a) = App (vToP' env f) (vToP' env a)
811-- | Replace every non-free reference to the name of a binding in
812-- the given term with a de Bruijn index.
813finalise :: Eq n => TT n -> TT n
814finalise (Bind x b sc) = Bind x (fmap finalise b) (pToV x (finalise sc))
815finalise (App f a) = App (finalise f) (finalise a)
818-- Once we've finished checking everything about a term we no longer need
819-- the type on the 'P' so erase it so save memory
821pEraseType :: TT n -> TT n
822pEraseType (P nt t _) = P nt t Erased
823pEraseType (App f a) = App (pEraseType f) (pEraseType a)
824pEraseType (Bind n b sc) = Bind n (fmap pEraseType b) (pEraseType sc)
827-- | As 'instantiate', but in addition to replacing @'V' 0@,
828-- replace references to the given 'Name'-like id.
829subst :: Eq n => n {-^ The id to replace -} ->
830 TT n {-^ The replacement term -} ->
831 TT n {-^ The term to replace in -} ->
833subst n v tm = instantiate v (pToV n tm)
835-- If there are no Vs in the term (i.e. in proof state)
836psubst :: Eq n => n -> TT n -> TT n -> TT n
837psubst n v tm = s' tm where
838 s' (P _ x _) | n == x = v
839 s' (Bind x b sc) | n == x = Bind x (fmap s' b) sc
840 | otherwise = Bind x (fmap s' b) (s' sc)
841 s' (App f a) = App (s' f) (s' a)
842 s' (Proj t idx) = Proj (s' t) idx
845-- | As 'subst', but takes a list of (name, substitution) pairs instead
846-- of a single name and substitution
847substNames :: Eq n => [(n, TT n)] -> TT n -> TT n
849substNames ((n, tm) : xs) t = subst n tm (substNames xs t)
851-- | Replaces all terms equal (in the sense of @(==)@) to
852-- the old term with the new term.
853substTerm :: Eq n => TT n {-^ Old term -} ->
854 TT n {-^ New term -} ->
855 TT n {-^ template term -}
857substTerm old new = st where
858 st t | t == old = new
859 st (App f a) = App (st f) (st a)
860 st (Bind x b sc) = Bind x (fmap st b) (st sc)
863-- | Returns true if V 0 and bound name n do not occur in the term
864noOccurrence :: Eq n => n -> TT n -> Bool
865noOccurrence n t = no' 0 t
867 no' i (V x) = not (i == x)
868 no' i (P Bound x _) = not (n == x)
869 no' i (Bind n b sc) = noB' i b && no' (i+1) sc
870 where noB' i (Let t v) = no' i t && no' i v
871 noB' i (Guess t v) = no' i t && no' i v
872 noB' i b = no' i (binderTy b)
873 no' i (App f a) = no' i f && no' i a
874 no' i (Proj x _) = no' i x
877-- | Returns all names used free in the term
878freeNames :: Eq n => TT n -> [n]
879freeNames (P _ n _) = [n]
880freeNames (Bind n (Let t v) sc) = nub $ freeNames v ++ (freeNames sc \\ [n])
882freeNames (Bind n b sc) = nub $ freeNames (binderTy b) ++ (freeNames sc \\ [n])
883freeNames (App f a) = nub $ freeNames f ++ freeNames a
884freeNames (Proj x i) = nub $ freeNames x
887-- | Return the arity of a (normalised) type
889arity (Bind n (Pi t) sc) = 1 + arity sc
892-- | Deconstruct an application; returns the function and a list of arguments
893unApply :: TT n -> (TT n, [TT n])
894unApply t = ua [] t where
895 ua args (App f a) = ua (a:args) f
896 ua args t = (t, args)
898-- | Returns a term representing the application of the first argument
899-- (a function) to every element of the second argument.
900mkApp :: TT n -> [TT n] -> TT n
902mkApp f (a:as) = mkApp (App f a) as
904unList :: Term -> Maybe [Term]
905unList tm = case unApply tm of
906 (nil, [_]) -> Just []
907 (cons, ([_, x, xs])) ->
912-- | Cast a 'TT' term to a 'Raw' value, discarding universe information and
913-- the types of named references and replacing all de Bruijn indices
914-- with the corresponding name. It is an error if there are free de
916forget :: TT Name -> Raw
919 fe env (P _ n _) = Var n
920 fe env (V i) = Var (env !! i)
921 fe env (Bind n b sc) = let n' = uniqueName n env in
922 RBind n' (fmap (fe env) b)
924 fe env (App f a) = RApp (fe env f) (fe env a)
927 fe env (TType i) = RType
928 fe env Erased = RConstant Forgot
930-- | Introduce a 'Bind' into the given term for each element of the
931-- given list of (name, binder) pairs.
932bindAll :: [(n, Binder (TT n))] -> TT n -> TT n
934bindAll ((n, b) : bs) t = Bind n b (bindAll bs t)
936-- | Like 'bindAll', but the 'Binder's are 'TT' terms instead.
937-- The first argument is a function to map @TT@ terms to @Binder@s.
938-- This function might often be something like 'Lam', which directly
939-- constructs a @Binder@ from a @TT@ term.
940bindTyArgs :: (TT n -> Binder (TT n)) -> [(n, TT n)] -> TT n -> TT n
941bindTyArgs b xs = bindAll (map (\ (n, ty) -> (n, b ty)) xs)
943-- | Return a list of pairs of the names of the outermost 'Pi'-bound
944-- variables in the given term, together with their types.
945getArgTys :: TT n -> [(n, TT n)]
946getArgTys (Bind n (Pi t) sc) = (n, t) : getArgTys sc
949getRetTy :: TT n -> TT n
950getRetTy (Bind n (PVar _) sc) = getRetTy sc
951getRetTy (Bind n (PVTy _) sc) = getRetTy sc
952getRetTy (Bind n (Pi _) sc) = getRetTy sc
955uniqueNameFrom :: [Name] -> [Name] -> Name
956uniqueNameFrom (s : supply) hs
957 | s `elem` hs = uniqueNameFrom supply hs
960uniqueName :: Name -> [Name] -> Name
961uniqueName n hs | n `elem` hs = uniqueName (nextName n) hs
964uniqueBinders :: [Name] -> TT Name -> TT Name
965uniqueBinders ns (Bind n b sc)
966 = let n' = uniqueName n ns in
967 Bind n' (fmap (uniqueBinders (n':ns)) b) (uniqueBinders ns sc)
968uniqueBinders ns (App f a) = App (uniqueBinders ns f) (uniqueBinders ns a)
969uniqueBinders ns t = t
972nextName (NS x s) = NS (nextName x) s
973nextName (MN i n) = MN (i+1) n
974nextName (UN x) = let (num', nm') = T.span isDigit (T.reverse x)
976 num = readN (T.reverse num') in
977 UN (nm `T.append` txt (show (num+1)))
979 readN x | not (T.null x) = read (T.unpack x)
981nextName (SN x) = SN (nextName' x)
983 nextName' (WhereN i f x) = WhereN i f (nextName x)
984 nextName' (CaseN n) = CaseN (nextName n)
985 nextName' (MethodN n) = MethodN (nextName n)
992-- | an environment with de Bruijn indices 'normalised' so that they all refer to
995newtype WkEnvTT n = Wk (EnvTT n)
996type WkEnv = WkEnvTT Name
998instance (Eq n, Show n) => Show (TT n) where
999 show t = showEnv [] t
1001itBitsName IT8 = "Bits8"
1002itBitsName IT16 = "Bits16"
1003itBitsName IT32 = "Bits32"
1004itBitsName IT64 = "Bits64"
1006instance Show Const where
1008 show (BI i) = show i
1009 show (Fl f) = show f
1010 show (Ch c) = show c
1011 show (Str s) = show s
1012 show (B8 x) = show x
1013 show (B16 x) = show x
1014 show (B32 x) = show x
1015 show (B64 x) = show x
1016 show (B8V x) = "<" ++ intercalate "," (map show (V.toList x)) ++ ">"
1017 show (B16V x) = "<" ++ intercalate "," (map show (V.toList x)) ++ ">"
1018 show (B32V x) = "<" ++ intercalate "," (map show (V.toList x)) ++ ">"
1019 show (B64V x) = "<" ++ intercalate "," (map show (V.toList x)) ++ ">"
1020 show (AType ATFloat) = "Float"
1021 show (AType (ATInt ITBig)) = "Integer"
1022 show (AType (ATInt ITNative)) = "Int"
1023 show (AType (ATInt ITChar)) = "Char"
1024 show (AType (ATInt (ITFixed it))) = itBitsName it
1025 show (AType (ATInt (ITVec it c))) = itBitsName it ++ "x" ++ show c
1026 show StrType = "String"
1027 show PtrType = "Ptr"
1028 show VoidType = "Void"
1030showEnv :: (Eq n, Show n) => EnvTT n -> TT n -> String
1031showEnv env t = showEnv' env t False
1032showEnvDbg env t = showEnv' env t True
1034prettyEnv env t = prettyEnv' env t False
1036 prettyEnv' env t dbg = prettySe 10 env t dbg
1038 bracket outer inner p
1039 | inner > outer = lparen <> p <> rparen
1042 prettySe p env (P nt n t) debug =
1045 lbrack <+> pretty nt <+> colon <+> prettySe 10 env t debug <+> rbrack
1048 prettySe p env (V i) debug
1051 text . show . fst $ env!!i
1053 lbrack <+> text (show i) <+> rbrack
1054 | otherwise = text "unbound" <+> text (show i) <+> text "!"
1055 prettySe p env (Bind n b@(Pi t) sc) debug
1056 | noOccurrence n sc && not debug =
1057 bracket p 2 $ prettySb env n b debug <> prettySe 10 ((n, b):env) sc debug
1058 prettySe p env (Bind n b sc) debug =
1059 bracket p 2 $ prettySb env n b debug <> prettySe 10 ((n, b):env) sc debug
1060 prettySe p env (App f a) debug =
1061 bracket p 1 $ prettySe 1 env f debug <+> prettySe 0 env a debug
1062 prettySe p env (Proj x i) debug =
1063 prettySe 1 env x debug <+> text ("!" ++ show i)
1064 prettySe p env (Constant c) debug = pretty c
1065 prettySe p env Erased debug = text "[_]"
1066 prettySe p env (TType i) debug = text "Type" <+> (text . show $ i)
1068 -- Render a `Binder` and its name
1069 prettySb env n (Lam t) = prettyB env "λ" "=>" n t
1070 prettySb env n (Hole t) = prettyB env "?defer" "." n t
1071 prettySb env n (Pi t) = prettyB env "(" ") ->" n t
1072 prettySb env n (PVar t) = prettyB env "pat" "." n t
1073 prettySb env n (PVTy t) = prettyB env "pty" "." n t
1074 prettySb env n (Let t v) = prettyBv env "let" "in" n t v
1075 prettySb env n (Guess t v) = prettyBv env "??" "in" n t v
1077 -- Use `op` and `sc` to delimit `n` (a binding name) and its type
1079 -- e.g. "λx : Int =>" for the Lam case
1080 prettyB env op sc n t debug =
1081 text op <> pretty n <+> colon <+> prettySe 10 env t debug <> text sc
1083 -- Like `prettyB`, but handle the bindings that have values in addition
1084 -- to names and types
1085 prettyBv env op sc n t v debug =
1086 text op <> pretty n <+> colon <+> prettySe 10 env t debug <+> text "=" <+>
1087 prettySe 10 env v debug <> text sc
1090showEnv' env t dbg = se 10 env t where
1091 se p env (P nt n t) = show n
1092 ++ if dbg then "{" ++ show nt ++ " : " ++ se 10 env t ++ "}" else ""
1093 se p env (V i) | i < length env && i >= 0
1094 = (show $ fst $ env!!i) ++
1095 if dbg then "{" ++ show i ++ "}" else ""
1096 | otherwise = "!!V " ++ show i ++ "!!"
1097 se p env (Bind n b@(Pi t) sc)
1098 | noOccurrence n sc && not dbg = bracket p 2 $ se 1 env t ++ " -> " ++ se 10 ((n,b):env) sc
1099 se p env (Bind n b sc) = bracket p 2 $ sb env n b ++ se 10 ((n,b):env) sc
1100 se p env (App f a) = bracket p 1 $ se 1 env f ++ " " ++ se 0 env a
1101 se p env (Proj x i) = se 1 env x ++ "!" ++ show i
1102 se p env (Constant c) = show c
1103 se p env Erased = "[__]"
1104 se p env Impossible = "[impossible]"
1105 se p env (TType i) = "Type " ++ show i
1107 sb env n (Lam t) = showb env "\\ " " => " n t
1108 sb env n (Hole t) = showb env "? " ". " n t
1109 sb env n (GHole i t) = showb env "?defer " ". " n t
1110 sb env n (Pi t) = showb env "(" ") -> " n t
1111 sb env n (PVar t) = showb env "pat " ". " n t
1112 sb env n (PVTy t) = showb env "pty " ". " n t
1113 sb env n (Let t v) = showbv env "let " " in " n t v
1114 sb env n (Guess t v) = showbv env "?? " " in " n t v
1116 showb env op sc n t = op ++ show n ++ " : " ++ se 10 env t ++ sc
1117 showbv env op sc n t v = op ++ show n ++ " : " ++ se 10 env t ++ " = " ++
1120 bracket outer inner str | inner > outer = "(" ++ str ++ ")"
1123-- | Check whether a term has any holes in it - impure if so
1124pureTerm :: TT Name -> Bool
1125pureTerm (App f a) = pureTerm f && pureTerm a
1126pureTerm (Bind n b sc) = notClassName n && pureBinder b && pureTerm sc where
1127 pureBinder (Hole _) = False
1128 pureBinder (Guess _ _) = False
1129 pureBinder (Let t v) = pureTerm t && pureTerm v
1130 pureBinder t = pureTerm (binderTy t)
1132 notClassName (MN _ c) | c == txt "class" = False
1133 notClassName _ = True
1137-- | Weaken a term by adding i to each de Bruijn index (i.e. lift it over i bindings)
1138weakenTm :: Int -> TT n -> TT n
1139weakenTm i t = wk i 0 t
1140 where wk i min (V x) | x >= min = V (i + x)
1141 wk i m (App f a) = App (wk i m f) (wk i m a)
1142 wk i m (Bind x b sc) = Bind x (wkb i m b) (wk i (m + 1) sc)
1144 wkb i m t = fmap (wk i m) t
1146-- | Weaken an environment so that all the de Bruijn indices are correct according
1147-- to the latest bound variable
1149weakenEnv :: EnvTT n -> EnvTT n
1150weakenEnv env = wk (length env - 1) env
1152 wk i ((n, b) : bs) = (n, weakenTmB i b) : wk (i - 1) bs
1153 weakenTmB i (Let t v) = Let (weakenTm i t) (weakenTm i v)
1154 weakenTmB i (Guess t v) = Guess (weakenTm i t) (weakenTm i v)
1155 weakenTmB i t = t { binderTy = weakenTm i (binderTy t) }
1157-- | Weaken every term in the environment by the given amount
1158weakenTmEnv :: Int -> EnvTT n -> EnvTT n
1159weakenTmEnv i = map (\ (n, b) -> (n, fmap (weakenTm i) b))
1161-- | Gather up all the outer 'PVar's and 'Hole's in an expression and reintroduce
1162-- them in a canonical order
1163orderPats :: Term -> Term
1164orderPats tm = op [] tm
1166 op ps (Bind n (PVar t) sc) = op ((n, PVar t) : ps) sc
1167 op ps (Bind n (Hole t) sc) = op ((n, Hole t) : ps) sc
1168 op ps sc = bindAll (sortP ps) sc
1170 sortP ps = pick [] (reverse ps)
1172 namesIn (P _ n _) = [n]
1173 namesIn (Bind n b t) = nub $ nb b ++ (namesIn t \\ [n])
1174 where nb (Let t v) = nub (namesIn t) ++ nub (namesIn v)
1175 nb (Guess t v) = nub (namesIn t) ++ nub (namesIn v)
1176 nb t = namesIn (binderTy t)
1177 namesIn (App f a) = nub (namesIn f ++ namesIn a)
1180 pick acc [] = reverse acc
1181 pick acc ((n, t) : ps) = pick (insert n t acc) ps
1183 insert n t [] = [(n, t)]
1184 insert n t ((n',t') : ps)
1185 | n `elem` (namesIn (binderTy t') ++
1186 concatMap namesIn (map (binderTy . snd) ps))
1187 = (n', t') : insert n t ps
1188 | otherwise = (n,t):(n',t'):ps
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list