This namespace creates an API by which this package can use a simple JavaScript implementation of OpenMath to store and manipulate mathematical expressions.
As documented on the main page, it is not necessary for you to use OpenMath. If you have your own class, you can create an object that wraps your expression class in an API spoken by this module, so that you need not convert your custom expression types to/from OpenMath.
To do so, create a single object that maps names of functions in this module's API to their implementations using your custom expression class. To see how to get started, and how to connect the resulting object to this module, see the second code example on the main page of this documentation.
Every function documented below is explained in two ways: First, the general requirement of that element of the API is described without reference to OpenMath specifically, so that those who are reading this for the purposes of writing their own expression API have that information in general terms. Secondly, the specifics of the OpenMath implementation in this file is described.
To enable you to write an API like the one below, your custom expression class must have the following features.
- It must be a hierarchical structure (as in filterSubexpressions) of objects that can be variables (or at least identifiers more broadly), function applications, bindings (that is, the application of quantifiers or quantifier-like symbols), and optionally other atomic expressions as well.
- It must be possible to tell when an instance is each of these things, so that you can write the essential functions isVariable, isApplication, and isBinding.
- It must be possible to construct instances of each type, so that you can write the essential functions variable, application, and binding.
- It must be possible to mark a variable with the "is a metavariable" boolean flag. If your expression class does not support attributes on expressions, you can do this using, for example, a prefix used only internally, as in the previous point. See the documentation for setMetavariable for more specifics on this idea. This enables you to write isMetavariable, setMetavariable, and clearMetavariable.
- It must be possible to query the essential details of each type of expression:
- For a variable, you must be able to write getVariableName.
- For an application, you must be able to write
getChildren. This treates the function application
like a LISP S-expression. For example,
3+5
would be seen as(+ 3 5)
and should therefore return three children. - For a binding, you must be able to write bindingHead (the quantifier or other head symbol), bindingVariables (the array of bound variables), bindingBody (the body inside the expression). For example, in the expression "for all x and y, x+y=y+x," the head is the universal quantifier (the "for all" symbol), the bound variables are x and y, and the body is the expression x+y=y+x.
- You must be able to write a function that checks whether a given instance of a given variable appears free in an ancestor expression. This should be do-able if your expression class can do all of the above things. See the documentation for variableIsFree for details.
- You must provide an expression (typically an atomic, like a symbol or variable) that will be used as the operator for metalinguistic expressions. (Such expressions arise when we write things like P(x) not as an expression in the language itself, but to mean the computation of an expression in the language by substituting x into a function P that generates expressions.) You can use any expression that will not be appearing naturally in any matching problem you provide to this package, so that there will be no confusion or ambiguity. An unusual symbol is sufficient, such as one named "_expression_function" or something equally unlikely to occur elsewhere.
- Source:
Methods
(static) application(children)
The application
function should construct a function application expression
whose children are in the array passed as the one parameter to this function.
The first child is the operator and the rest are its operands, as in an a LISP
S-expression, such as (* 3 5)
for "3 times 5." The exact objects in the
list given should be used; this function should not make copies.
The OpenMath implementation uses a constructor with a similar purpose that is built into the OpenMath module.
Parameters:
Name | Type | Description |
---|---|---|
children |
Array.<OM> | the children of the resulting application, the first of which should be the operator and the rest the operands |
- Source:
(static) binding(symbol, variables, body)
The binding
function should construct a binding expression whose head is the
given symbol (typically the quantifier if that's what type of expression it is),
whose bound variables are in the array given as the second parameter, and whose
body is the third expression given. For example, to construct the expression
"for all x, P" (for any expression P), pass three arguments: The "for all"
symbol, the JavaScript array containing just the variable expression x, and
finally the expression P. The exact objects in the arguments should be used;
this function should not make copies.
The OpenMath implementation uses a constructor with a similar purpose that is built into the OpenMath module.
Parameters:
Name | Type | Description |
---|---|---|
symbol |
OM | the binding operator |
variables |
Array.<OM> | the array of bound variables |
body |
OM | the body of the binding |
- Source:
(static) bindingBody(binding)
The bindingBody
function is typically called with a binding
expression, as one might construct using the
binding function. This function should
return its body, that is, the last argument given to the
binding constructor, which is typically the main
expression in the binding. The original body expression must be
returned, not a copy. If the given expression does not
pass the isBinding check, this function should
return null.
The OpenMath implementation stores the body internally, so we can simply return that here.
Parameters:
Name | Type | Description |
---|---|---|
binding |
OM | the expression whose body is to be returned (the original body, not a copy) |
- Source:
(static) bindingHead(expr)
The bindingHead
function will typically be called with a binding
expression, as one might construct using the
binding function. This function should
return its head symbol, that is, the first argument given to the
binding constructor, which is typically the quantifier
(if the expression is a quantification). The original symbol must be
returned, not a copy. If the given expression does not
pass the isBinding check, this function should
return null.
The OpenMath implementation stores the symbol internally, so we can simply return that here.
Parameters:
Name | Type | Description |
---|---|---|
expr |
OM | the expression whose operator is to be returned |
- Source:
(static) bindingVariables(binding)
The bindingVariables
function is typically called with a binding
expression, as one might construct using the
binding function. This function should
return all of its bound variables, that is, the array passed as second
parameter to the
binding constructor. The exact objects must be
returned, not copies, and they should be in a JavaScript array. If the given
expression does not pass the isBinding check, this
function should return null.
The OpenMath implementation stores the bound variables in an array internally, so we can simply return that array here. Although we could slice it to ensure it will not get corrupted, the other code in this module does not alter bound variable arrays that it has queried from expressions, so this implementation is safe for our purposes.
Parameters:
Name | Type | Description |
---|---|---|
binding |
OM | the expression whose bound variables are to be returned |
- Source:
(static) clearMetavariable(metavariable)
The clearMetavariable
function removes the attribute or mark set in
setMetavariable, if indeed such an attribute
exists on the given expression. This should restore the variable to its
original condition.
The OpenMath implementation removes any attribute with the same key used in setMetavariable.
Parameters:
Name | Type | Description |
---|---|---|
metavariable |
OM | the metavariable to be unmarked |
- Source:
(static) copy(expr)
The copy
function must create a deep copy of an expression and return the
new copy.
The OpenMath library provides a copy function that we use here.
Parameters:
Name | Type | Description |
---|---|---|
expr |
OM | the expression to copy |
- Source:
(static) equal(expr1, expr2)
The equal
function computes deep structural equality, which can be true even
if the two objects are not the same in memory. Any two expressions that have
the same hierarchical structure should be considered equal.
The OpenMath library provides a structural equality function, and we defer to that.
Parameters:
Name | Type | Description |
---|---|---|
expr1 |
OM | first expression |
expr2 |
OM | second expression |
- Source:
(static) getChildren(expr)
The getChildren
function can expect that the input object is a function
application expression, as one might construct using the
application function. This function should
return all of its children, that is, the array passed to the
application constructor, in the same order
(operator first, operands in order thereafter). The exact children must be
returned, not copies, and they should be in a JavaScript array. If the given
expression does not pass the isApplication check,
this function should return an empty array.
The OpenMath implementation stores the children in an array internally, so we can simply return that array here. Although we could slice it to ensure it will not get corrupted, the other code in this module does not alter child arrays that it has queried from expressions, so this implementation is safe for our purposes.
Parameters:
Name | Type | Description |
---|---|---|
expr |
OM | the expression whose children should be returned |
- Source:
(static) getVariableName(variable)
The getVariableName
function must return, as a string, the name of the
variable stored in the given expression. If the given expression does not
pass the isVariable check, this function should
return null.
The OpenMath implementation uses the built-in .name
attribute of OpenMath
variable instances.
Parameters:
Name | Type | Description |
---|---|---|
variable |
OM | an OM instance of type variable |
- Source:
(static) getVariablesIn(expression)
Parameters:
Name | Type | Description |
---|---|---|
expression |
OM | the expression to be checked |
- Source:
Returns:
(static) isApplication(expr)
The isApplication
function should return true if and only if the given
expression is a function application. This excludes other compound expression
types, particularly binding expressions (that is, applications of quantifiers).
The OpenMath implementation relies on the fact that "application" is a built-in OpenMath type.
Parameters:
Name | Type | Description |
---|---|---|
expr |
OM | the expression to test |
- Source:
(static) isBinding(expr)
The isBinding
function should return true if and only if the given
expression is a binding expression, that is, the application of a quantifier,
such as "there exists x such that x-1=0". This excludes other compound expression
types, particularly function application (that is, where no dummy variables are
used/bound, like the x in the example just given).
The OpenMath implementation relies on the fact that "binding" is a built-in OpenMath type.
Parameters:
Name | Type | Description |
---|---|---|
expr |
OM | the expression to test |
- Source:
(static) isExpression(expr)
The isExpression
function must return true if and only if the one input
is an instance of the class of expressions.
In the OpenMath case, we provide a function that returns true if and only if the given object is an OpenMath expression.
Parameters:
Name | Type | Description |
---|---|---|
expr |
object | the object to test |
- Source:
(static) isMetavariable(variable)
The isMetavariable
function returns true if and only if the given argument
is a variable or symbol and the attribute or mark described in
setMetavariable is present on it.
The OpenMath implementation checks whether there is an attribute with the same key-value pair used in setMetavariable.
Parameters:
Name | Type | Description |
---|---|---|
variable |
OM | the variable to be checked |
- Source:
(static) isVariable(expr)
The isVariable
function must return true if and only if the given expression
is a variable. That is, the expression class for which we are defining an API
must have a notion of variable (or at least "identifier") and this function
must return true if and only if the given expression is that kind.
The OpenMath implementation here looks up the OpenMath type and checks to see if it is the "variable" type defined in the OpenMath standard.
Parameters:
Name | Type | Description |
---|---|---|
expr |
OM | the expression to test |
- Source:
(static) replace(toReplace, withThis)
The replace
function should find where its first argument sits inside any
parent structure, remove it from that location, and then place the second
parameter in that place instead. No specific return value is required.
If the first parameter does not have a parent, this function is permitted to
do nothing.
The OpenMath library has a function that does this. While it also updates the internal references of the parameters, this extra behavior does not harm the results of this function.
Parameters:
Name | Type | Description |
---|---|---|
toReplace |
OM | the expression to be replaced |
withThis |
OM | the expression with which to replace it |
- Source:
(static) sameType(expr1, expr2)
The sameType
function must return true if and only if two expressions have
the same type. This does not require an expression class to have an extensive
type system, but it must at least distinguish three broad types of expressions:
atomic expressions must be different from function applications, which are both
different from bindings (that is, the application of a quantifier or other
binding symbol, such as a summation or integral). Any type system that is at
least as granular as this basic minimum is sufficient.
Here we simply look up the OpenMath type
of each object and compare them,
because OpenMath has types for application, binding, and several different
types of atomic expressions (among other things).
Parameters:
Name | Type | Description |
---|---|---|
expr1 |
OM | first expression |
expr2 |
OM | second expression |
- Source:
(static) setMetavariable(variable)
The setMetavariable
function takes an expression as input. If it is not
a variable or symbol, this function does nothing. But if it is, then this
function adds to it an attribute (or any kind of mark) that will distinguish
the variable as a metavariable. Note these important attributes of this mark:
- It affects only this instance of the variable. Other variables with the same name are not marked.
- It affects copies made later of this instance. That is, copying this instance should copy the mark as well.
- A test of equality between two variables of the same name, but one being a metavariable and the other not, should yield a false result (not equal). But two non-metavariables with the same name are equal, as are two metavariables with the same name.
The purpose of metavariables need not be documented here, but briefly, they are used when pattern matching, to distinguish a variable that can match against any expression from a variable that can match only other instances of itself.
If your expression class doesn't support adding attributes to expressions, you could use prefixes or suffixes to distinguish metavariables from non-metavariables.
The OpenMath implementation uses the fact that OpenMath expressions can be decorated with an arbitrary number of attributes. We use one whose key is a special symbol defined earlier and whose value is the constant "true."
Parameters:
Name | Type | Description |
---|---|---|
variable |
OM | the variable to be marked |
- Source:
(static) variable(name)
The variable
function constructs an instance of your expression class that
is a variable with the given name.
The OpenMath implementation uses a constructor with a similar purpose that is built into the OpenMath module.
Parameters:
Name | Type | Description |
---|---|---|
name |
string | the name of the new variable |
- Source:
(static) variableIsFree(variable, expression)
The variableIsFree
function will be called with a variable expression
as the first argument and some other expression as its second argument.
(If the second argument is null or omitted, the topmost ancestor should
be treated as the default value.) It should return true if and only if
the variable (not a copy of the variable, but the given instance) appears
in the given expression, not within the scope of a binding expression that
binds the variable (that is, whose list of bound variables includes a
variable of the same name).
The OpenMath implementation has a more general isFree
function that works
for variables or larger expressions, and we can simply defer to that.
Parameters:
Name | Type | Description |
---|---|---|
variable |
OM | the variable (not its name, but the actual instance) whose freeness will be tested |
expression |
OM | the ancestor expression containing the variable, and in which we are asking whether it is free |
- Source: