Constants are symbols that have a name and several optional components, namely
Examples for constants include mathematical constants, functions, axioms, theorems and inference rules. Their concrete syntax is
The order of the object-level components is arbitrary. They are seperated by the object-delimiter , the constant declaration itself is delimited by . Aliases are simply alternative names that can be used to refer to the constant and are useful e.g. in structures (see below).
t, then the term
thas to be inhabitable (see ???).
|- <definition> : <type>has to hold.
A notation is an arbitrary sequence of tokens, optionally followed by
<precedence>is an arbitrary integer signifying the precedence (i.e. binding strength) of the notation.
This allows for almost arbitrary notation definitions.
Example: The notation for an infix operation
+could be given by
# 1 + 2 prec 10. If a notation for a multiplication has a higher precedence (and thus a higher binding strength), e.g.
# 1 ⋅ 2 prec 15, we can omit parentheses according to standard mathematical convention, so the expression
a + b ⋅ cwould be correctly parsed as
a + (b ⋅ c).
Argument positions not given in a notation are assumed to be implicit, i.e. they have to be inferrable during type checking. This can be the case, if dependent type constructors are in scope, e.g. dependent products.
Example: A constant
cwith type takes two arguments: an
x:F(a). Obviously, the second argument depends on the first, which allows MMT to infer the first argument from the second. So
ccould have a notation
# c 2omitting the first argument.
Roles serve as metadata-like annotations to constants. In most situations they are simply ignored. The following list of roles have some special meaning:
role Eqindicates that the constant represents an equality that can be used for rewriting.
role Judgmentindicates that the constant is a Curry-Howard-style operator mapping propositions to types - as such, occurences of the symbol indicate theorems or axioms.
role Simplifyrequires the type of the constant to be of the form
⊦ f(g(a)) ≐ b, where
Eq. This induces a rewrite rule, that simplifies instances of the left side of the equation to the right side during type checking.
Large MMT theories are usually built modularly from smaller ones. The central declaration is that of an import between two theories. Similar to the ML module system, MMT supports unnamed imports, called includes and named imports, called structures.
Both make the contents of some theory
<domain> available to the current one.
Structures may additionally modify the imported theory, most importantly by instantiating constants with concrete values in the importing theory.
The syntax for a theory inclusion is
The include-relation between theories generates a partial order. In particular, includes are composed transitively, and including the same theory twice is redundant.
The syntax for structures is
<declarations> is a sequence of declarations.
<domain>, all other components are inherited from the latter. In particular, structures can introduce definitions for (not necessarily) previously undefined constants, in which case the (new) definition has to have the (induced/old) type of the constant. It is recommended to never override the type of a symbol in a structure.
<declname>in a structure
<struct>in a module
<mod> ? <struct> / <declname>. It is this declaration, that is visible from the outside and can be used in subsequent (to the structure) declarations. In contrast, the URI
<mod> / <struct> ? <declname>refers to the plain declaration as declared directly in the structure, i.e. without inheritance. The latter should never be used outside of the API and is invisible to declarations outside of the structure.
<domain>are not redundant. Each structure introduces fresh (possibly modified) copies of the declarations in the domain.
s2have corresponding domains
dom2with the same meta theory
meta, then everything in the dependency closure of
metawill be included exactly once.
Implementation note: Because includes and structures are often treated exactly the same way, the MMT system represents an include as a structure with empty body and the induced name
Let us assume, we have a theory
Monoid with a constant
G for the domain of a monoid,
op for the monoid operation,
unit for the unit of the monoid and the usual axioms. The latter might be included in (and extended by) a theory
AbelianGroup adding the additional axioms. then we can use structures to form a theory
Ring, using the theory
Monoid for multiplication and
AbelianGroup for addition. If we use includes, like this
the (transitively twice) included instances of
Monoid will be identified, defeating the purpose. As mentioned above, named structures prevent that, and allow us to additionally
times) and of
opnew desired notations.
Thus, the correct theory
Ring could look like this:
All the monoid/group axioms are imported via the structures and are thus available for the respective new symbols. If
AbelianGroup have the same meta theory (e.g.
first_order_logic), then all symbols imported via that (e.g. quantifiers, logical connectives etc.) are identified across the two structures.
Rules are special Scala objects that can be declared in an MMT theory Thy to change the semantics of Thy-terms. For example,
are provided as rules.
Users typically do not need to use rules except when designing their own type systems outside logical frameworks.
To declare a rule, just write
rule PATH inside Thy, where
PATH is the MMT URI of a Scala object on the current class path - MMT will dynamically load the Scala object and use it in all Thy-algorithms.