Istari

Term syntax

Istari employs two types for terms: Term.term is the internal representation of terms, and ETerm.eterm is the external representation. We usually refer to both of them as just terms, except when the context requires us to distinguish them.

The main difference between internal and external terms is that internal terms represent variables using de Bruijn indices, while external terms use explicit names. (Istari’s de Bruijn indices count from zero.) External terms are converted to internal ones by supplying a data structure (called a directory) that maps names onto indices. (A few other things are done while converting external terms to internal ones as well.)

The term grammar

The default grammar for terms is as follows. Capitalized words are nonterminals; lower case words are keywords. (Exception: U and Kind are keywords.)

Forms are listed in increasing order of precedence. Grouped forms have the same precedence. A subterm at the same level of precedence is given in brackets. For example, [Term] + Term indicates that addition is left associative, while Term :: [Term] indicates that cons is right associative.

Term ::=
  fn Bindingsn . [Term]                                          (lambda)
  forall Bindings . [Term]                                       (dependent product)  
  exists Bindings . [Term]                                       (strong dependent sum)
  iforall Bindings . [Term]                                      (impredicative universal)
  iexists Bindings . [Term]                                      (impredicative existential)
  intersect Bindings . [Term]                                    (intersection type)
  union Bindings . [Term]                                        (intersection type)
  foralltp OIdents . [Term]                                      (impredicative polymorphism)
  rec Ident . [Term]                                             (recursive type)
  mu Ident . [Term]                                              (inductive type)
  wtype ( Ident : [Term] ) . [Term]                              (W type)
  iset ( Ident : [Term] ) . [Term]                               (intensional set type)
  quotient ( Ident Ident : [Term] ) . [Term]                     (quotient type)
  Term -> [Term]                                                 (ordinary arrow)
  Term -t> [Term]                                                (tarrow kind)
  Term -k> [Term]                                                (karrow kind)
  Term -g> [Term]                                                (guard)
  let Ident = Term in [Term]                                     (let)
  let next Ident = Term in [Term]                                (scoped future elim)
  seq Ident = Term in [Term]                                     (eager let for partial types)
  seqt Ident = Term in [Term]                                    (eager let for total types)
  case Term of | inl OIdent . [Term] | inr OIdent . [Term]       (sum elim)
  Term : [Term]                                                  (typing)
  Term : type                                                    (type formation)
  fnind ... inductive function ...                               (inductive function)

  if [Term] then [Term] else [Term]                              (if-then-else)

  Term <-> Term                                                  (if-and-only-if)

  Term % [Term]                                                  (sum type)

  Term & [Term]                                                  (product type)
  Term &d [Term]                                                 (semi-dependent product type)
  Term &g [Term]                                                 (coguard type)

  Term = Term : Term                                             (equality)
  Term = Term : type                                             (type equality)
  Term <: Term                                                   (subtyping)
  Term <:> Term                                                  (extensional type equivalence)
  Term != Term : Term                                            (inequality)
  Term <= Term                                                   (natural number inequality)
  Term < Term                                                    (natural number inequality)
  Term <l= Term                                                  (level inequality)
  Term <z= Term                                                  (integer inequality)
  Term <z Term                                                   (integer inequality)

  Term :: [Term]                                                 (cons)

  [Term] + Term                                                  (natural number plus)
  [Term] - Term                                                  (natural number minus)
  [Term] +z Term                                                 (integer plus)
  [Term] -z Term                                                 (integer minus)

  [Term] * Term                                                  (natural number times)
  [Term] *z Term                                                 (integer times)

  [Term] Term                                                    (application)
  [Term] #1                                                      (first projection)
  [Term] #2                                                      (second projection)
  [Term] #prev                                                   (unscoped future elim)
  [Term] ## Number                                               (#2 ... #2 #1)
  pi1 Term                                                       (first projection)
  pi2 Term                                                       (second projection)
  prev Term                                                      (unscoped future elim)
  next Term                                                      (future intro)
  inl Term                                                       (sum intro)
  inr Term                                                       (sum intro)
  ~z Term                                                        (integer negation)
  U Level                                                        (universe)
  Kind Level                                                     (kind)
  [Term] :> Term                                                 (type annotation)
  [Term] ap Term                                                 (visibilized application)
  [Term] _# Number                                               (application to multiple evars)
  [Term] __# Number                                              (application to multiple holes)

  ( Term )
  ()                                                             (unit)
  ( Term , ... , Term )                                          (tuple, length at least 2)
  { Ident : Term | Term }                                        (set type)
  { Term }                                                       (squashed type)
  Longident                                                      (identifier)
  Number                                                         (natural number literal)
  _                                                              (evar)
  __                                                             (hole)
  \ ... antiquoted internal term ... \
  ` Longident
  l` LTerm                                                       (literal term)
  level` Level                                                   (level expression)
  z` Number                                                      (integer literal)

OIdent ::=
  Ident
  _                                                              (anonymous argument)

OIdents ::=
  OIdent ... OIdent                                              (length can be zero)

Binding ::=
  OIdent                                                         (unannotated binding)
  (OIdents : Term)                                               (binding with type supplied)

Bindings ::=       
  Binding ... Binding                                            (length at least 0)

Bindingsn ::=       
  Binding ... Binding                                            (length at least 1)

Level ::=
  Number + [Level]                                               (level plus)

  ( Level )
  Number                                                         (level literal)
  [ Level ... Level ]                                            (level max, length at least 1)
  Ident                                                          (identifier)
  \ ... antiquoted internal term ... \

Notes:

Literal terms

The LTerm (“literal term”) grammar represents internal terms directly. It uses de Bruijn indices rather than names and offers very few conveniences. It also provides a notation for explicit substitution.

LTerm ::=
  fn . [LTerm]                                                   (lambda)

  LTerm = LTerm : LTerm                                          (equality)
  LTerm = LTerm : type                                           (type equality)

  [LTerm] LTerm                                                  (application)
  [LTerm] #1                                                     (first projection)
  [LTerm] #2                                                     (second projection)
  [LTerm] #prev                                                  (unscoped future elim)
  next LTerm                                                     (future intro)

  [LTerm] [ Sub ]                                                (substitution)

  ( LTerm )
  ()                                                             (unit)
  ( LTerm, LTerm )                                               (pair)
  U                                                              (universe w/o argument)
  Number                                                         (de Bruijn index)
  \ ... antiquoted internal term ... \
  ` Longident
  z` Number                                                      (integer literal)

Sub ::=
  [Sub] o Sub                                                    (composition)

  LTerm . [Sub]                                                  (substitution cons)
  Number . [Sub]                                                 (special case of cons)
  ^ Number                                                       (shift)
  id                                                             (identity, same as ^ 0)
  ( Sub )

Notes:

Parsing functions

Most of the nonterminals above can be parsed by various pervasive functions: parseIdent, parseIdents, parseLongident, parseOIdent, parseOIdents, parseBinding, parseBindings, parseLTerm, parseSub.

These functions are all actually the identity function, but IML is instructed to parse their argument using the indicated nonterminal.

Implicit and invisible arguments

Some constants take implicit and/or invisible arguments:

For example, List.map has type:

intersect i . forall (a b : U i) . (a -> b) -> list a -> list b

and has two implicit arguments. Thus, its first argument (i) is invisible, and its second and third arguments (a and b) are implicit. Normally one calls List.map with just the explicit arguments; so List.map F L means:

`List.map _ _ F L

If, instead, one wanted to supply all the arguments, one would write something like:

`List.map ap I A B F L

The ap I fills in the invisible argument, while the starting tick suppresses the insertion of evars for implicit arguments, so A and B can be supplied.

Note that implicit arguments are inserted first, so List.map ap I F L would mean:

`List.map _ _ ap I F L`

which is probably not desired. But rarely would one want to give only the invisible arguments explicitly anyway.

Opacity

Constants have one of five levels of opacity: soft, firm, soft-strict, hard, or opaque:

                  OPAQUE
                    |
                   HARD
                 /      \
            FIRM          SOFT_STRICT
                 \      /
                   SOFT

A constant’s opacity can be altered using the function setOpacity. Since opacities can be altered, an opaque constant is not entirely abstract. To make a constant abstract, one may delete a constant’s definition, thereby rendering it permanently opaque, using the function abstract.

(* abbreviated *)
signature CONSTANT =
   sig
      ...

      datatype opacity = SOFT | FIRM | SOFT_STRICT | HARD | OPAQUE

      (* returns the constant's definition if the constant is not OPAQUE *)
      val definition : constant -> term option

      val opacity : constant -> opacity
      val setOpacity : constant -> opacity -> unit

      (* sets opacity to OPAQUE and deletes the definition (cannot be reversed) *)
      val abstract : constant -> unit
   end

structure Constant : CONSTANT

The Constant.setOpacity function is pervasive and it parses its first argument as a constant, so a constant’s opacity can be easily set by executing setOpacity /foo/ Constant.SOFT, for example.