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.Maybe (listToMaybe)
33import Data.Vector.Unboxed (Vector)
34import qualified Data.Vector.Unboxed as V
35import qualified Data.Binary as B
36import Data.Binary hiding (get, put)
37import Foreign.Storable (sizeOf)
39import Util.Pretty hiding (Str)
41data Option = TTypeInTType
45-- | Source location. These are typically produced by the parser 'Idris.Parser.getFC'
46data FC = FC { fc_fname :: String, -- ^ Filename
47 fc_start :: (Int, Int), -- ^ Line and column numbers for the start of the location span
48 fc_end :: (Int, Int) -- ^ Line and column numbers for the end of the location span
51-- | Ignore source location equality (so deriving classes do not compare FCs)
56newtype FC' = FC' { unwrapFC :: FC }
59 FC' fc == FC' fc' = fcEq fc fc'
60 where fcEq (FC n s e) (FC n' s' e') = n == n' && s == s' && e == e'
62-- | Empty source location
66-- | Source location with file only
68fileFC s = FC s (0, 0) (0, 0)
71deriving instance Binary FC
72deriving instance NFData FC
75instance Sized FC where
76 size (FC f s e) = 4 + length f
79 show (FC f s e) = f ++ ":" ++ showLC s e
80 where showLC (sl, sc) (el, ec) | sl == el && sc == ec = show sl ++ ":" ++ show sc
81 | sl == el = show sl ++ ":" ++ show sc ++ "-" ++ show ec
82 | otherwise = show sl ++ ":" ++ show sc ++ "-" ++ show el ++ ":" ++ show ec
84-- | Output annotation for pretty-printed name - decides colour
85data NameOutput = TypeOutput | FunOutput | DataOutput | MetavarOutput
87-- | Text formatting output
88data TextFormatting = BoldText | ItalicText | UnderlineText
90-- | Output annotations for pretty-printing
91data OutputAnnotation = AnnName Name (Maybe NameOutput) (Maybe String) (Maybe String)
92 -- ^^ The name, classification, docs overview, and pretty-printed type
93 | AnnBoundName Name Bool
94 -- ^^ The name and whether it is implicit
99 | AnnTextFmt TextFormatting
101-- | Used for error reflection
102data ErrorReportPart = TextPart String
105 | SubReport [ErrorReportPart]
109-- Please remember to keep Err synchronised with
110-- Language.Reflection.Errors.Err in the stdlib!
112-- | Idris errors. Used as exceptions in the compiler, but reported to users
113-- if they reach the top level.
117 | CantUnify Bool t t (Err' t) [(Name, t)] Int
118 -- Int is 'score' - how much we did unify
119 -- Bool indicates recoverability, True indicates more info may make
120 -- unification succeed
121 | InfiniteUnify Name t [(Name, t)]
122 | CantConvert t t [(Name, t)]
123 | CantSolveGoal t [(Name, t)]
124 | UnifyScope Name Name t [(Name, t)]
125 | CantInferType String
126 | NonFunctionType t t
128 | TooManyArguments Name
130 | NoSuchVariable Name
134 | CantResolveAlts [String]
139 | NonCollapsiblePostulate Name
140 | AlreadyDefined Name
141 | ProofSearchFail (Err' t)
144 | Elaborating String Name (Err' t)
145 | ElaboratingArg Name Name [(Name, Name)] (Err' t)
146 | ProviderError String
147 | LoadingFailed String (Err' t)
148 | ReflectionError [[ErrorReportPart]] (Err' t)
149 | ReflectionFailed String (Err' t)
150 deriving (Eq, Functor)
155deriving instance NFData Err
158instance Sized Err where
159 size (Msg msg) = length msg
160 size (InternalMsg msg) = length msg
161 size (CantUnify _ left right err _ score) = size left + size right + size err
162 size (InfiniteUnify _ right _) = size right
163 size (CantConvert left right _) = size left + size right
164 size (UnifyScope _ _ right _) = size right
165 size (NoSuchVariable name) = size name
166 size (NoTypeDecl name) = size name
167 size (NotInjective l c r) = size l + size c + size r
168 size (CantResolve trm) = size trm
169 size (NoRewriting trm) = size trm
170 size (CantResolveAlts _) = 1
171 size (IncompleteTerm trm) = size trm
172 size UniverseError = 1
173 size ProgramLineComment = 1
174 size (At fc err) = size fc + size err
175 size (Elaborating _ n err) = size err
176 size (ElaboratingArg _ _ _ err) = size err
177 size (ProviderError msg) = length msg
178 size (LoadingFailed fn e) = 1 + length fn + size e
182score (CantUnify _ _ _ m _ s) = s + score m
183score (CantResolve _) = 20
184score (NoSuchVariable _) = 1000
185score (ProofSearchFail _) = 10000
186score (CantSolveGoal _ _) = 10000
187score (InternalMsg _) = -1
190instance Show Err where
192 show (InternalMsg s) = "Internal error: " ++ show s
193 show (CantUnify _ l r e sc i) = "CantUnify " ++ show l ++ " " ++ show r ++ " "
194 ++ show e ++ " in " ++ show sc ++ " " ++ show i
195 show (CantSolveGoal g _) = "CantSolve " ++ show g
196 show (Inaccessible n) = show n ++ " is not an accessible pattern variable"
197 show (ProviderError msg) = "Type provider error: " ++ msg
198 show (LoadingFailed fn e) = "Loading " ++ fn ++ " failed: (TT) " ++ show e
199 show ProgramLineComment = "Program line next to comment"
200 show (At f e) = show f ++ ":" ++ show e
201 show (ElaboratingArg f x prev e) = "Elaborating " ++ show f ++ " arg " ++
202 show x ++ ": " ++ show e
203 show (Elaborating what n e) = "Elaborating " ++ what ++ show n ++ ":" ++ show e
206instance Pretty Err OutputAnnotation where
207 pretty (Msg m) = text m
208 pretty (CantUnify _ l r e _ i) =
209 text "Cannot unify" <+> colon <+> pretty l <+> text "and" <+> pretty r <+>
210 nest nestingSize (text "where" <+> pretty e <+> text "with" <+> (text . show $ i))
211 pretty (ProviderError msg) = text msg
212 pretty err@(LoadingFailed _ _) = text (show err)
213 pretty _ = text "Error"
215instance Error Err where
220instance (Pretty a OutputAnnotation) => Pretty (TC a) OutputAnnotation where
221 pretty (OK ok) = pretty ok
223 text "Error" <+> colon <+> pretty err
225instance Show a => Show (TC a) where
227 show (Error str) = "Error: " ++ show str
232failMsg :: String -> TC a
233failMsg str = Error (Msg str)
235trun :: FC -> TC a -> TC a
237trun fc (Error e) = Error (At fc e)
239discard :: Monad m => m a -> m ()
240discard f = f >> return ()
242showSep :: String -> [String] -> String
245showSep sep (x:xs) = x ++ sep ++ showSep sep xs
247pmap f (x, y) = (f x, f y)
249traceWhen True msg a = trace msg a
250traceWhen False _ a = a
252-- RAW TERMS ----------------------------------------------------------------
254-- | Names are hierarchies of strings, describing scope (so no danger of
255-- duplicate names, but need to be careful on lookup).
256data Name = UN T.Text -- ^ User-provided name
257 | NS Name [T.Text] -- ^ Root, namespaces
258 | MN Int T.Text -- ^ Machine chosen names
259 | NErased -- ^ Name of somethng which is never used in scope
260 | SN SpecialName -- ^ Decorated function names
261 | SymRef Int -- ^ Reference to IBC file symbol table (used during serialisation)
264txt :: String -> T.Text
267str :: T.Text -> String
270tnull :: T.Text -> Bool
273thead :: T.Text -> Char
276-- Smart constructors for names, using old String style
280sNS :: Name -> [String] -> Name
281sNS n ss = NS n (map txt ss)
283sMN :: Int -> String -> Name
284sMN i s = MN i (txt s)
287deriving instance Binary Name
288deriving instance NFData Name
291data SpecialName = WhereN Int Name Name
292 | InstanceN Name [T.Text]
293 | ParentN Name T.Text
300deriving instance Binary SpecialName
301deriving instance NFData SpecialName
304sInstanceN :: Name -> [String] -> SpecialName
305sInstanceN n ss = InstanceN n (map T.pack ss)
307sParentN :: Name -> String -> SpecialName
308sParentN n s = ParentN n (T.pack s)
310instance Sized Name where
312 size (NS n els) = 1 + length els
316instance Pretty Name OutputAnnotation where
317 pretty n@(UN n') = annotate (AnnName n Nothing Nothing Nothing) $ text (T.unpack n')
318 pretty n@(NS un s) = annotate (AnnName n Nothing Nothing Nothing) . noAnnotate $ pretty un
319 pretty n@(MN i s) = annotate (AnnName n Nothing Nothing Nothing) $
320 lbrace <+> text (T.unpack s) <+> (text . show $ i) <+> rbrace
321 pretty n@(SN s) = annotate (AnnName n Nothing Nothing Nothing) $ text (show s)
323instance Pretty [Name] OutputAnnotation where
324 pretty = encloseSep empty empty comma . map pretty
326instance Show Name where
328 show (NS n s) = showSep "." (map T.unpack (reverse s)) ++ "." ++ show n
329 show (MN _ u) | u == txt "underscore" = "_"
330 show (MN i s) = "{" ++ str s ++ show i ++ "}"
334instance Show SpecialName where
335 show (WhereN i p c) = show p ++ ", " ++ show c
336 show (InstanceN cl inst) = showSep ", " (map T.unpack inst) ++ " instance of " ++ show cl
337 show (MethodN m) = "method " ++ show m
338 show (ParentN p c) = show p ++ "#" ++ T.unpack c
339 show (CaseN n) = "case block in " ++ show n
340 show (ElimN n) = "<<" ++ show n ++ " eliminator>>"
341 show (InstanceCtorN n) = "constructor of " ++ show n
343-- Show a name in a way decorated for code generation, not human reading
344showCG :: Name -> String
345showCG (UN n) = T.unpack n
346showCG (NS n s) = showSep "." (map T.unpack (reverse s)) ++ "." ++ showCG n
347showCG (MN _ u) | u == txt "underscore" = "_"
348showCG (MN i s) = "{" ++ T.unpack s ++ show i ++ "}"
349showCG (SN s) = showCG' s
350 where showCG' (WhereN i p c) = showCG p ++ ":" ++ showCG c ++ ":" ++ show i
351 showCG' (InstanceN cl inst) = '@':showCG cl ++ '$':showSep ":" (map T.unpack inst)
352 showCG' (MethodN m) = '!':showCG m
353 showCG' (ParentN p c) = showCG p ++ "#" ++ show c
354 showCG' (CaseN c) = showCG c ++ "_case"
355 showCG' (ElimN sn) = showCG sn ++ "_elim"
359-- |Contexts allow us to map names to things. A root name maps to a collection
360-- of things in different namespaces with that name.
361type Ctxt a = Map.Map Name (Map.Map Name a)
362emptyContext = Map.empty
364mapCtxt :: (a -> b) -> Ctxt a -> Ctxt b
367-- |Return True if the argument 'Name' should be interpreted as the name of a
369tcname (UN xs) | T.null xs = False
370 | otherwise = T.head xs == '@'
371tcname (NS n _) = tcname n
372tcname (SN (InstanceN _ _)) = True
373tcname (SN (MethodN _)) = True
374tcname (SN (ParentN _ _)) = True
377implicitable (NS n _) = implicitable n
378implicitable (UN xs) | T.null xs = False
379 | otherwise = isLower (T.head xs)
380implicitable (MN _ _) = True
381implicitable _ = False
386addDef :: Name -> a -> Ctxt a -> Ctxt a
387addDef n v ctxt = case Map.lookup (nsroot n) ctxt of
388 Nothing -> Map.insert (nsroot n)
389 (Map.insert n v Map.empty) ctxt
390 Just xs -> Map.insert (nsroot n)
391 (Map.insert n v xs) ctxt
393{-| Look up a name in the context, given an optional namespace.
394 The name (n) may itself have a (partial) namespace given.
396 Rules for resolution:
398 - if an explicit namespace is given, return the names which match it. If none
399 match, return all names.
401 - if the name has has explicit namespace given, return the names which match it
402 and ignore the given namespace.
404 - otherwise, return all names.
408lookupCtxtName :: Name -> Ctxt a -> [(Name, a)]
409lookupCtxtName n ctxt = case Map.lookup (nsroot n) ctxt of
410 Just xs -> filterNS (Map.toList xs)
414 filterNS ((found, v) : xs)
415 | nsmatch n found = (found, v) : filterNS xs
416 | otherwise = filterNS xs
418 nsmatch (NS n ns) (NS p ps) = ns `isPrefixOf` ps
419 nsmatch (NS _ _) _ = False
420 nsmatch looking found = True
422lookupCtxt :: Name -> Ctxt a -> [a]
423lookupCtxt n ctxt = map snd (lookupCtxtName n ctxt)
425lookupCtxtExact :: Name -> Ctxt a -> Maybe a
426lookupCtxtExact n ctxt = listToMaybe [ v | (nm, v) <- lookupCtxtName n ctxt, nm == n]
428updateDef :: Name -> (a -> a) -> Ctxt a -> Ctxt a
430 = let ds = lookupCtxtName n ctxt in
431 foldr (\ (n, t) c -> addDef n (f t) c) ctxt ds
433toAlist :: Ctxt a -> [(Name, a)]
434toAlist ctxt = let allns = map snd (Map.toList ctxt) in
435 concat (map (Map.toList) allns)
437addAlist :: Show a => [(Name, a)] -> Ctxt a -> Ctxt a
438addAlist [] ctxt = ctxt
439addAlist ((n, tm) : ds) ctxt = addDef n tm (addAlist ds ctxt)
441data NativeTy = IT8 | IT16 | IT32 | IT64
442 deriving (Show, Eq, Ord, Enum)
444instance Pretty NativeTy OutputAnnotation where
445 pretty IT8 = text "Bits8"
446 pretty IT16 = text "Bits16"
447 pretty IT32 = text "Bits32"
448 pretty IT64 = text "Bits64"
450data IntTy = ITFixed NativeTy | ITNative | ITBig | ITChar
452 deriving (Show, Eq, Ord)
454intTyName :: IntTy -> String
455intTyName ITNative = "Int"
456intTyName ITBig = "BigInt"
457intTyName (ITFixed sized) = "B" ++ show (nativeTyWidth sized)
458intTyName (ITChar) = "Char"
459intTyName (ITVec ity count) = "B" ++ show (nativeTyWidth ity) ++ "x" ++ show count
461data ArithTy = ATInt IntTy | ATFloat -- TODO: Float vectors
462 deriving (Show, Eq, Ord)
464deriving instance NFData IntTy
465deriving instance NFData NativeTy
466deriving instance NFData ArithTy
469instance Pretty ArithTy OutputAnnotation where
470 pretty (ATInt ITNative) = text "Int"
471 pretty (ATInt ITBig) = text "BigInt"
472 pretty (ATInt ITChar) = text "Char"
473 pretty (ATInt (ITFixed n)) = pretty n
474 pretty (ATInt (ITVec e c)) = pretty e <> text "x" <> (text . show $ c)
475 pretty ATFloat = text "Float"
477nativeTyWidth :: NativeTy -> Int
479nativeTyWidth IT16 = 16
480nativeTyWidth IT32 = 32
481nativeTyWidth IT64 = 64
483{-# DEPRECATED intTyWidth "Non-total function, use nativeTyWidth and appropriate casing" #-}
484intTyWidth :: IntTy -> Int
485intTyWidth (ITFixed n) = nativeTyWidth n
486intTyWidth ITNative = 8 * sizeOf (0 :: Int)
487intTyWidth ITChar = error "IRTS.Lang.intTyWidth: Characters have platform and backend dependent width"
488intTyWidth ITBig = error "IRTS.Lang.intTyWidth: Big integers have variable width"
490data Const = I Int | BI Integer | Fl Double | Ch Char | Str String
491 | B8 Word8 | B16 Word16 | B32 Word32 | B64 Word64
492 | B8V (Vector Word8) | B16V (Vector Word16)
493 | B32V (Vector Word32) | B64V (Vector Word64)
494 | AType ArithTy | StrType
495 | PtrType | ManagedPtrType | BufferType | VoidType | Forgot
498deriving instance Binary Const
499deriving instance NFData Const
502instance Sized Const where
505instance Pretty Const OutputAnnotation where
506 pretty (I i) = text . show $ i
507 pretty (BI i) = text . show $ i
508 pretty (Fl f) = text . show $ f
509 pretty (Ch c) = text . show $ c
510 pretty (Str s) = text s
511 pretty (AType a) = pretty a
512 pretty StrType = text "String"
513 pretty BufferType = text "prim__UnsafeBuffer"
514 pretty PtrType = text "Ptr"
515 pretty ManagedPtrType = text "Ptr"
516 pretty VoidType = text "Void"
517 pretty Forgot = text "Forgot"
518 pretty (B8 w) = text . show $ w
519 pretty (B16 w) = text . show $ w
520 pretty (B32 w) = text . show $ w
521 pretty (B64 w) = text . show $ w
524 | RBind Name (Binder Raw) Raw
531instance Sized Raw where
533 size (RBind name bind right) = 1 + size bind + size right
534 size (RApp left right) = 1 + size left + size right
536 size (RForce raw) = 1 + size raw
537 size (RConstant const) = size const
539instance Pretty Raw OutputAnnotation where
543deriving instance Binary Raw
544deriving instance NFData Raw
547-- The type parameter `b` will normally be something like `TT Name` or just
548-- `Raw`. We do not make a type-level distinction between TT terms that happen
549-- to be TT types and TT terms that are not TT types.
550-- | All binding forms are represented in a uniform fashion. This type only represents
551-- the types of bindings (and their values, if any); the attached identifiers are part
552-- of the 'Bind' constructor for the 'TT' type.
553data Binder b = Lam { binderTy :: !b {-^ type annotation for bound variable-}}
554 | Pi { binderTy :: !b }
555 {-^ A binding that occurs in a function type expression, e.g. @(x:Int) -> ...@ -}
556 | Let { binderTy :: !b,
557 binderVal :: b {-^ value for bound variable-}}
558 -- ^ A binding that occurs in a @let@ expression
559 | NLet { binderTy :: !b,
561 | Hole { binderTy :: !b}
562 | GHole { envlen :: Int,
564 | Guess { binderTy :: !b,
566 | PVar { binderTy :: !b }
567 -- ^ A pattern variable
568 | PVTy { binderTy :: !b }
569 deriving (Show, Eq, Ord, Functor)
571deriving instance Binary Binder
572deriving instance NFData Binder
575instance Sized a => Sized (Binder a) where
576 size (Lam ty) = 1 + size ty
577 size (Pi ty) = 1 + size ty
578 size (Let ty val) = 1 + size ty + size val
579 size (NLet ty val) = 1 + size ty + size val
580 size (Hole ty) = 1 + size ty
581 size (GHole _ ty) = 1 + size ty
582 size (Guess ty val) = 1 + size ty + size val
583 size (PVar ty) = 1 + size ty
584 size (PVTy ty) = 1 + size ty
586fmapMB :: Monad m => (a -> m b) -> Binder a -> m (Binder b)
587fmapMB f (Let t v) = liftM2 Let (f t) (f v)
588fmapMB f (NLet t v) = liftM2 NLet (f t) (f v)
589fmapMB f (Guess t v) = liftM2 Guess (f t) (f v)
590fmapMB f (Lam t) = liftM Lam (f t)
591fmapMB f (Pi t) = liftM Pi (f t)
592fmapMB f (Hole t) = liftM Hole (f t)
593fmapMB f (GHole i t) = liftM (GHole i) (f t)
594fmapMB f (PVar t) = liftM PVar (f t)
595fmapMB f (PVTy t) = liftM PVTy (f t)
597raw_apply :: Raw -> [Raw] -> Raw
599raw_apply f (a : as) = raw_apply (RApp f a) as
601raw_unapply :: Raw -> (Raw, [Raw])
602raw_unapply t = ua [] t where
603 ua args (RApp f a) = ua (a:args) f
604 ua args t = (t, args)
606-- WELL TYPED TERMS ---------------------------------------------------------
608-- | Universe expressions for universe checking
609data UExp = UVar Int -- ^ universe variable
610 | UVal Int -- ^ explicit universe level
613deriving instance NFData UExp
616instance Sized UExp where
619-- We assume that universe levels have been checked, so anything external
620-- can just have the same universe variable and we won't get any new
623instance Binary UExp where
625 get = return (UVar (-1))
627instance Show UExp where
628 show (UVar x) | x < 26 = [toEnum (x + fromEnum 'a')]
629 | otherwise = toEnum ((x `mod` 26) + fromEnum 'a') : show (x `div` 26)
630 show (UVal x) = show x
631-- show (UMax l r) = "max(" ++ show l ++ ", " ++ show r ++")"
633-- | Universe constraints
634data UConstraint = ULT UExp UExp -- ^ Strictly less than
635 | ULE UExp UExp -- ^ Less than or equal to
638instance Show UConstraint where
639 show (ULT x y) = show x ++ " < " ++ show y
640 show (ULE x y) = show x ++ " <= " ++ show y
642type UCs = (Int, [UConstraint])
646 | DCon {nt_tag :: Int, nt_arity :: Int} -- ^ Data constructor
647 | TCon {nt_tag :: Int, nt_arity :: Int} -- ^ Type constructor
650deriving instance Binary NameType
651deriving instance NFData NameType
654instance Sized NameType where
657instance Pretty NameType OutputAnnotation where
660instance Eq NameType where
661 Bound == Bound = True
663 DCon _ a == DCon _ b = (a == b) -- ignore tag
664 TCon _ a == TCon _ b = (a == b) -- ignore tag
667-- | Terms in the core language. The type parameter is the type of
668-- identifiers used for bindings and explicit named references;
669-- usually we use @TT 'Name'@.
670data TT n = P NameType n (TT n) -- ^ named references with type
671 -- (P for "Parameter", motivated by McKinna and Pollack's
672 -- Pure Type Systems Formalized)
673 | V !Int -- ^ a resolved de Bruijn-indexed variable
674 | Bind n !(Binder (TT n)) (TT n) -- ^ a binding
675 | App !(TT n) (TT n) -- ^ function, function type, arg
676 | Constant Const -- ^ constant
677 | Proj (TT n) !Int -- ^ argument projection; runtime only
678 -- (-1) is a special case for 'subtract one from BI'
679 | Erased -- ^ an erased term
680 | Impossible -- ^ special case for totality checking
681 | TType UExp -- ^ the type of types at some level
682 deriving (Ord, Functor)
684deriving instance Binary TT
685deriving instance NFData TT
688class TermSize a where
689 termsize :: Name -> a -> Int
691instance TermSize a => TermSize [a] where
693 termsize n (x : xs) = termsize n x + termsize n xs
695instance TermSize (TT Name) where
696 termsize n (P _ n' _)
697 | n' == n = 1000000 -- recursive => really big
700 -- for `Bind` terms, we can erroneously declare a term
701 -- "recursive => really big" if the name of the bound
702 -- variable is the same as the name we're using
703 -- So generate a different name in that case.
704 termsize n (Bind n' (Let t v) sc)
705 = let rn = if n == n' then sMN 0 "noname" else n in
706 termsize rn v + termsize rn sc
707 termsize n (Bind n' b sc)
708 = let rn = if n == n' then sMN 0 "noname" else n in
710 termsize n (App f a) = termsize n f + termsize n a
711 termsize n (Proj t i) = termsize n t
714instance Sized a => Sized (TT a) where
715 size (P name n trm) = 1 + size name + size n + size trm
717 size (Bind nm binder bdy) = 1 + size nm + size binder + size bdy
718 size (App l r) = 1 + size l + size r
719 size (Constant c) = size c
721 size (TType u) = 1 + size u
723instance Pretty a o => Pretty (TT a) o where
724 pretty _ = text "test"
726type EnvTT n = [(n, Binder (TT n))]
728data Datatype n = Data { d_typename :: n,
731 d_cons :: [(n, TT n)] }
732 deriving (Show, Functor, Eq)
734instance Eq n => Eq (TT n) where
735 (==) (P xt x _) (P yt y _) = x == y
736 (==) (V x) (V y) = x == y
737 (==) (Bind _ xb xs) (Bind _ yb ys) = xs == ys && xb == yb
738 (==) (App fx ax) (App fy ay) = ax == ay && fx == fy
739 (==) (TType _) (TType _) = True -- deal with constraints later
740 (==) (Constant x) (Constant y) = x == y
741 (==) (Proj x i) (Proj y j) = x == y && i == j
746-- * A few handy operations on well typed terms:
748-- | A term is injective iff it is a data constructor, type constructor,
749-- constant, the type Type, pi-binding, or an application of an injective
751isInjective :: TT n -> Bool
752isInjective (P (DCon _ _) _ _) = True
753isInjective (P (TCon _ _) _ _) = True
754isInjective (Constant _) = True
755isInjective (TType x) = True
756isInjective (Bind _ (Pi _) sc) = True
757isInjective (App f a) = isInjective f
760-- | Count the number of instances of a de Bruijn index in a term
761vinstances :: Int -> TT n -> Int
762vinstances i (V x) | i == x = 1
763vinstances i (App f a) = vinstances i f + vinstances i a
764vinstances i (Bind x b sc) = instancesB b + vinstances (i + 1) sc
765 where instancesB (Let t v) = vinstances i v
769-- | Replace the outermost (index 0) de Bruijn variable with the given term
770instantiate :: TT n -> TT n -> TT n
771instantiate e = subst 0 where
772 subst i (V x) | i == x = e
773 subst i (Bind x b sc) = Bind x (fmap (subst i) b) (subst (i+1) sc)
774 subst i (App f a) = App (subst i f) (subst i a)
775 subst i (Proj x idx) = Proj (subst i x) idx
778-- | As 'instantiate', but also decrement the indices of all de Bruijn variables
779-- remaining in the term, so that there are no more references to the variable
780-- that has been substituted.
781substV :: TT n -> TT n -> TT n
782substV x tm = dropV 0 (instantiate x tm) where
783 dropV i (V x) | x > i = V (x - 1)
785 dropV i (Bind x b sc) = Bind x (fmap (dropV i) b) (dropV (i+1) sc)
786 dropV i (App f a) = App (dropV i f) (dropV i a)
787 dropV i (Proj x idx) = Proj (dropV i x) idx
790-- | Replace all non-free de Bruijn references in the given term with references
791-- to the name of their binding.
792explicitNames :: TT n -> TT n
793explicitNames (Bind x b sc) = let b' = fmap explicitNames b in
795 (explicitNames (instantiate
796 (P Bound x (binderTy b')) sc))
797explicitNames (App f a) = App (explicitNames f) (explicitNames a)
798explicitNames (Proj x idx) = Proj (explicitNames x) idx
801-- | Replace references to the given 'Name'-like id with references to
803pToV :: Eq n => n -> TT n -> TT n
805pToV' n i (P _ x _) | n == x = V i
806pToV' n i (Bind x b sc)
807-- We can assume the inner scope has been pToVed already, so continue to
808-- resolve names from the *outer* scope which may happen to have the same id.
809 | n == x = Bind x (fmap (pToV' n i) b) sc
810 | otherwise = Bind x (fmap (pToV' n i) b) (pToV' n (i+1) sc)
811pToV' n i (App f a) = App (pToV' n i f) (pToV' n i a)
812pToV' n i (Proj t idx) = Proj (pToV' n i t) idx
815-- increase de Bruijn indices, as if a binder has been added
816addBinder :: TT n -> TT n
819 ab top (V i) | i >= top = V (i + 1)
821 ab top (Bind x b sc) = Bind x (fmap (ab top) b) (ab (top + 1) sc)
822 ab top (App f a) = App (ab top f) (ab top a)
823 ab top (Proj t idx) = Proj (ab top t) idx
826-- | Convert several names. First in the list comes out as V 0
827pToVs :: Eq n => [n] -> TT n -> TT n
828pToVs ns tm = pToVs' ns tm 0 where
830 pToVs' (n:ns) tm i = pToV' n i (pToVs' ns tm (i+1))
832-- | Replace de Bruijn indices in the given term with explicit references to
833-- the names of the bindings they refer to. It is an error if the given term
834-- contains free de Bruijn indices.
837 vToP' env (V i) = let (n, b) = (env !! i) in
838 P Bound n (binderTy b)
839 vToP' env (Bind n b sc) = let b' = fmap (vToP' env) b in
840 Bind n b' (vToP' ((n, b'):env) sc)
841 vToP' env (App f a) = App (vToP' env f) (vToP' env a)
844-- | Replace every non-free reference to the name of a binding in
845-- the given term with a de Bruijn index.
846finalise :: Eq n => TT n -> TT n
847finalise (Bind x b sc) = Bind x (fmap finalise b) (pToV x (finalise sc))
848finalise (App f a) = App (finalise f) (finalise a)
851-- Once we've finished checking everything about a term we no longer need
852-- the type on the 'P' so erase it so save memory
854pEraseType :: TT n -> TT n
855pEraseType (P nt t _) = P nt t Erased
856pEraseType (App f a) = App (pEraseType f) (pEraseType a)
857pEraseType (Bind n b sc) = Bind n (fmap pEraseType b) (pEraseType sc)
860-- | As 'instantiate', but in addition to replacing @'V' 0@,
861-- replace references to the given 'Name'-like id.
862subst :: Eq n => n {-^ The id to replace -} ->
863 TT n {-^ The replacement term -} ->
864 TT n {-^ The term to replace in -} ->
866subst n v tm = instantiate v (pToV n tm)
868-- If there are no Vs in the term (i.e. in proof state)
869psubst :: Eq n => n -> TT n -> TT n -> TT n
870psubst n v tm = s' tm where
871 s' (P _ x _) | n == x = v
872 s' (Bind x b sc) | n == x = Bind x (fmap s' b) sc
873 | otherwise = Bind x (fmap s' b) (s' sc)
874 s' (App f a) = App (s' f) (s' a)
875 s' (Proj t idx) = Proj (s' t) idx
878-- | As 'subst', but takes a list of (name, substitution) pairs instead
879-- of a single name and substitution
880substNames :: Eq n => [(n, TT n)] -> TT n -> TT n
882substNames ((n, tm) : xs) t = subst n tm (substNames xs t)
884-- | Replaces all terms equal (in the sense of @(==)@) to
885-- the old term with the new term.
886substTerm :: Eq n => TT n {-^ Old term -} ->
887 TT n {-^ New term -} ->
888 TT n {-^ template term -}
890substTerm old new = st where
891 st t | t == old = new
892 st (App f a) = App (st f) (st a)
893 st (Bind x b sc) = Bind x (fmap st b) (st sc)
896-- | Returns true if V 0 and bound name n do not occur in the term
897noOccurrence :: Eq n => n -> TT n -> Bool
898noOccurrence n t = no' 0 t
900 no' i (V x) = not (i == x)
901 no' i (P Bound x _) = not (n == x)
902 no' i (Bind n b sc) = noB' i b && no' (i+1) sc
903 where noB' i (Let t v) = no' i t && no' i v
904 noB' i (Guess t v) = no' i t && no' i v
905 noB' i b = no' i (binderTy b)
906 no' i (App f a) = no' i f && no' i a
907 no' i (Proj x _) = no' i x
910-- | Returns all names used free in the term
911freeNames :: Eq n => TT n -> [n]
912freeNames (P _ n _) = [n]
913freeNames (Bind n (Let t v) sc) = nub $ freeNames v ++ (freeNames sc \\ [n])
915freeNames (Bind n b sc) = nub $ freeNames (binderTy b) ++ (freeNames sc \\ [n])
916freeNames (App f a) = nub $ freeNames f ++ freeNames a
917freeNames (Proj x i) = nub $ freeNames x
920-- | Return the arity of a (normalised) type
922arity (Bind n (Pi t) sc) = 1 + arity sc
925-- | Deconstruct an application; returns the function and a list of arguments
926unApply :: TT n -> (TT n, [TT n])
927unApply t = ua [] t where
928 ua args (App f a) = ua (a:args) f
929 ua args t = (t, args)
931-- | Returns a term representing the application of the first argument
932-- (a function) to every element of the second argument.
933mkApp :: TT n -> [TT n] -> TT n
935mkApp f (a:as) = mkApp (App f a) as
937unList :: Term -> Maybe [Term]
938unList tm = case unApply tm of
939 (nil, [_]) -> Just []
940 (cons, ([_, x, xs])) ->
945-- | Cast a 'TT' term to a 'Raw' value, discarding universe information and
946-- the types of named references and replacing all de Bruijn indices
947-- with the corresponding name. It is an error if there are free de
949forget :: TT Name -> Raw
952 fe env (P _ n _) = Var n
953 fe env (V i) = Var (env !! i)
954 fe env (Bind n b sc) = let n' = uniqueName n env in
955 RBind n' (fmap (fe env) b)
957 fe env (App f a) = RApp (fe env f) (fe env a)
960 fe env (TType i) = RType
961 fe env Erased = RConstant Forgot
963-- | Introduce a 'Bind' into the given term for each element of the
964-- given list of (name, binder) pairs.
965bindAll :: [(n, Binder (TT n))] -> TT n -> TT n
967bindAll ((n, b) : bs) t = Bind n b (bindAll bs t)
969-- | Like 'bindAll', but the 'Binder's are 'TT' terms instead.
970-- The first argument is a function to map @TT@ terms to @Binder@s.
971-- This function might often be something like 'Lam', which directly
972-- constructs a @Binder@ from a @TT@ term.
973bindTyArgs :: (TT n -> Binder (TT n)) -> [(n, TT n)] -> TT n -> TT n
974bindTyArgs b xs = bindAll (map (\ (n, ty) -> (n, b ty)) xs)
976-- | Return a list of pairs of the names of the outermost 'Pi'-bound
977-- variables in the given term, together with their types.
978getArgTys :: TT n -> [(n, TT n)]
979getArgTys (Bind n (Pi t) sc) = (n, t) : getArgTys sc
982getRetTy :: TT n -> TT n
983getRetTy (Bind n (PVar _) sc) = getRetTy sc
984getRetTy (Bind n (PVTy _) sc) = getRetTy sc
985getRetTy (Bind n (Pi _) sc) = getRetTy sc
988uniqueNameFrom :: [Name] -> [Name] -> Name
989uniqueNameFrom (s : supply) hs
990 | s `elem` hs = uniqueNameFrom supply hs
993uniqueName :: Name -> [Name] -> Name
994uniqueName n hs | n `elem` hs = uniqueName (nextName n) hs
997uniqueBinders :: [Name] -> TT Name -> TT Name
998uniqueBinders ns (Bind n b sc)
999 = let n' = uniqueName n ns in
1000 Bind n' (fmap (uniqueBinders (n':ns)) b) (uniqueBinders ns sc)
1001uniqueBinders ns (App f a) = App (uniqueBinders ns f) (uniqueBinders ns a)
1002uniqueBinders ns t = t
1005nextName (NS x s) = NS (nextName x) s
1006nextName (MN i n) = MN (i+1) n
1007nextName (UN x) = let (num', nm') = T.span isDigit (T.reverse x)
1009 num = readN (T.reverse num') in
1010 UN (nm `T.append` txt (show (num+1)))
1012 readN x | not (T.null x) = read (T.unpack x)
1014nextName (SN x) = SN (nextName' x)
1016 nextName' (WhereN i f x) = WhereN i f (nextName x)
1017 nextName' (CaseN n) = CaseN (nextName n)
1018 nextName' (MethodN n) = MethodN (nextName n)
1023type Env = EnvTT Name
1025-- | an environment with de Bruijn indices 'normalised' so that they all refer to
1028newtype WkEnvTT n = Wk (EnvTT n)
1029type WkEnv = WkEnvTT Name
1031instance (Eq n, Show n) => Show (TT n) where
1032 show t = showEnv [] t
1034itBitsName IT8 = "Bits8"
1035itBitsName IT16 = "Bits16"
1036itBitsName IT32 = "Bits32"
1037itBitsName IT64 = "Bits64"
1039instance Show Const where
1041 show (BI i) = show i
1042 show (Fl f) = show f
1043 show (Ch c) = show c
1044 show (Str s) = show s
1045 show (B8 x) = show x
1046 show (B16 x) = show x
1047 show (B32 x) = show x
1048 show (B64 x) = show x
1049 show (B8V x) = "<" ++ intercalate "," (map show (V.toList x)) ++ ">"
1050 show (B16V x) = "<" ++ intercalate "," (map show (V.toList x)) ++ ">"
1051 show (B32V x) = "<" ++ intercalate "," (map show (V.toList x)) ++ ">"
1052 show (B64V x) = "<" ++ intercalate "," (map show (V.toList x)) ++ ">"
1053 show (AType ATFloat) = "Float"
1054 show (AType (ATInt ITBig)) = "Integer"
1055 show (AType (ATInt ITNative)) = "Int"
1056 show (AType (ATInt ITChar)) = "Char"
1057 show (AType (ATInt (ITFixed it))) = itBitsName it
1058 show (AType (ATInt (ITVec it c))) = itBitsName it ++ "x" ++ show c
1059 show StrType = "String"
1060 show BufferType = "prim__UnsafeBuffer"
1061 show PtrType = "Ptr"
1062 show ManagedPtrType = "ManagedPtr"
1063 show VoidType = "Void"
1065showEnv :: (Eq n, Show n) => EnvTT n -> TT n -> String
1066showEnv env t = showEnv' env t False
1067showEnvDbg env t = showEnv' env t True
1069prettyEnv env t = prettyEnv' env t False
1071 prettyEnv' env t dbg = prettySe 10 env t dbg
1073 bracket outer inner p
1074 | inner > outer = lparen <> p <> rparen
1077 prettySe p env (P nt n t) debug =
1080 lbracket <+> pretty nt <+> colon <+> prettySe 10 env t debug <+> rbracket
1083 prettySe p env (V i) debug
1086 text . show . fst $ env!!i
1088 lbracket <+> text (show i) <+> rbracket
1089 | otherwise = text "unbound" <+> text (show i) <+> text "!"
1090 prettySe p env (Bind n b@(Pi t) sc) debug
1091 | noOccurrence n sc && not debug =
1092 bracket p 2 $ prettySb env n b debug <> prettySe 10 ((n, b):env) sc debug
1093 prettySe p env (Bind n b sc) debug =
1094 bracket p 2 $ prettySb env n b debug <> prettySe 10 ((n, b):env) sc debug
1095 prettySe p env (App f a) debug =
1096 bracket p 1 $ prettySe 1 env f debug <+> prettySe 0 env a debug
1097 prettySe p env (Proj x i) debug =
1098 prettySe 1 env x debug <+> text ("!" ++ show i)
1099 prettySe p env (Constant c) debug = pretty c
1100 prettySe p env Erased debug = text "[_]"
1101 prettySe p env (TType i) debug = text "Type" <+> (text . show $ i)
1103 -- Render a `Binder` and its name
1104 prettySb env n (Lam t) = prettyB env "λ" "=>" n t
1105 prettySb env n (Hole t) = prettyB env "?defer" "." n t
1106 prettySb env n (Pi t) = prettyB env "(" ") ->" n t
1107 prettySb env n (PVar t) = prettyB env "pat" "." n t
1108 prettySb env n (PVTy t) = prettyB env "pty" "." n t
1109 prettySb env n (Let t v) = prettyBv env "let" "in" n t v
1110 prettySb env n (Guess t v) = prettyBv env "??" "in" n t v
1112 -- Use `op` and `sc` to delimit `n` (a binding name) and its type
1114 -- e.g. "λx : Int =>" for the Lam case
1115 prettyB env op sc n t debug =
1116 text op <> pretty n <+> colon <+> prettySe 10 env t debug <> text sc
1118 -- Like `prettyB`, but handle the bindings that have values in addition
1119 -- to names and types
1120 prettyBv env op sc n t v debug =
1121 text op <> pretty n <+> colon <+> prettySe 10 env t debug <+> text "=" <+>
1122 prettySe 10 env v debug <> text sc
1125showEnv' env t dbg = se 10 env t where
1126 se p env (P nt n t) = show n
1127 ++ if dbg then "{" ++ show nt ++ " : " ++ se 10 env t ++ "}" else ""
1128 se p env (V i) | i < length env && i >= 0
1129 = (show $ fst $ env!!i) ++
1130 if dbg then "{" ++ show i ++ "}" else ""
1131 | otherwise = "!!V " ++ show i ++ "!!"
1132 se p env (Bind n b@(Pi t) sc)
1133 | noOccurrence n sc && not dbg = bracket p 2 $ se 1 env t ++ " -> " ++ se 10 ((n,b):env) sc
1134 se p env (Bind n b sc) = bracket p 2 $ sb env n b ++ se 10 ((n,b):env) sc
1135 se p env (App f a) = bracket p 1 $ se 1 env f ++ " " ++ se 0 env a
1136 se p env (Proj x i) = se 1 env x ++ "!" ++ show i
1137 se p env (Constant c) = show c
1138 se p env Erased = "[__]"
1139 se p env Impossible = "[impossible]"
1140 se p env (TType i) = "Type " ++ show i
1142 sb env n (Lam t) = showb env "\\ " " => " n t
1143 sb env n (Hole t) = showb env "? " ". " n t
1144 sb env n (GHole i t) = showb env "?defer " ". " n t
1145 sb env n (Pi t) = showb env "(" ") -> " n t
1146 sb env n (PVar t) = showb env "pat " ". " n t
1147 sb env n (PVTy t) = showb env "pty " ". " n t
1148 sb env n (Let t v) = showbv env "let " " in " n t v
1149 sb env n (Guess t v) = showbv env "?? " " in " n t v
1151 showb env op sc n t = op ++ show n ++ " : " ++ se 10 env t ++ sc
1152 showbv env op sc n t v = op ++ show n ++ " : " ++ se 10 env t ++ " = " ++
1155 bracket outer inner str | inner > outer = "(" ++ str ++ ")"
1158-- | Check whether a term has any holes in it - impure if so
1159pureTerm :: TT Name -> Bool
1160pureTerm (App f a) = pureTerm f && pureTerm a
1161pureTerm (Bind n b sc) = notClassName n && pureBinder b && pureTerm sc where
1162 pureBinder (Hole _) = False
1163 pureBinder (Guess _ _) = False
1164 pureBinder (Let t v) = pureTerm t && pureTerm v
1165 pureBinder t = pureTerm (binderTy t)
1167 notClassName (MN _ c) | c == txt "class" = False
1168 notClassName _ = True
1172-- | Weaken a term by adding i to each de Bruijn index (i.e. lift it over i bindings)
1173weakenTm :: Int -> TT n -> TT n
1174weakenTm i t = wk i 0 t
1175 where wk i min (V x) | x >= min = V (i + x)
1176 wk i m (App f a) = App (wk i m f) (wk i m a)
1177 wk i m (Bind x b sc) = Bind x (wkb i m b) (wk i (m + 1) sc)
1179 wkb i m t = fmap (wk i m) t
1181-- | Weaken an environment so that all the de Bruijn indices are correct according
1182-- to the latest bound variable
1184weakenEnv :: EnvTT n -> EnvTT n
1185weakenEnv env = wk (length env - 1) env
1187 wk i ((n, b) : bs) = (n, weakenTmB i b) : wk (i - 1) bs
1188 weakenTmB i (Let t v) = Let (weakenTm i t) (weakenTm i v)
1189 weakenTmB i (Guess t v) = Guess (weakenTm i t) (weakenTm i v)
1190 weakenTmB i t = t { binderTy = weakenTm i (binderTy t) }
1192-- | Weaken every term in the environment by the given amount
1193weakenTmEnv :: Int -> EnvTT n -> EnvTT n
1194weakenTmEnv i = map (\ (n, b) -> (n, fmap (weakenTm i) b))
1196-- | Gather up all the outer 'PVar's and 'Hole's in an expression and reintroduce
1197-- them in a canonical order
1198orderPats :: Term -> Term
1199orderPats tm = op [] tm
1201 op ps (Bind n (PVar t) sc) = op ((n, PVar t) : ps) sc
1202 op ps (Bind n (Hole t) sc) = op ((n, Hole t) : ps) sc
1203 op ps sc = bindAll (sortP ps) sc
1205 sortP ps = pick [] (reverse ps)
1207 namesIn (P _ n _) = [n]
1208 namesIn (Bind n b t) = nub $ nb b ++ (namesIn t \\ [n])
1209 where nb (Let t v) = nub (namesIn t) ++ nub (namesIn v)
1210 nb (Guess t v) = nub (namesIn t) ++ nub (namesIn v)
1211 nb t = namesIn (binderTy t)
1212 namesIn (App f a) = nub (namesIn f ++ namesIn a)
1215 pick acc [] = reverse acc
1216 pick acc ((n, t) : ps) = pick (insert n t acc) ps
1218 insert n t [] = [(n, t)]
1219 insert n t ((n',t') : ps)
1220 | n `elem` (namesIn (binderTy t') ++
1221 concatMap namesIn (map (binderTy . snd) ps))
1222 = (n', t') : insert n t ps
1223 | 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