Patterns and Rules
Recognizing patterns and applying rules is a powerful symbolic computing tool to identify and manipulate the structure of expressions.
Wildcards
Wildcard are placeholders identifiers in an expression. They start with a _
.
The "_"
universal wildcard matches anything that is in the corresponding
position in an expression.
The "__"
wildcard matches any sequence of 1 or more expressions in its
corresponding position. It is useful to capture the arguments of a function.
The "___"
wildcard matches any sequence of 0 or more expressions in its
corresponding position.
A wildcard symbol may include a name which is used to capture the matching
expression, for example _a
.
When using a named wildcard, all instances of the named wildcard must match. In contrast, an un-named wildcard
(a universal wildcard such as "_"
"__"
or "___"
) can be used multiple
times to match different values.
Patterns
A pattern is an expression which can include one or more placeholders in the form of wildcards.
Patterns are similar to Regular Expressions in traditional programming languages but they are tailored to deal with MathJSON expressions instead of strings.
Given a pattern and an expression the goal of pattern matching is to find a substitution for all the wildcards such that the pattern becomes the expression.
An expression is said to match a pattern if there exists a set of values such that replacing the wildcards with those values is equal to the expression. This set of values is called a substitution.
For example, the pattern ["Add", 3, "_c"]
becomes the expression
["Add", 3, "x"]
by replacing the wildcard "_c"
with "x"
. The substitution
is therefore {_c : "x"}
.
On the other hand, the expression ["Divide", "x", 2]
does not match the
pattern ["Add", 3, "_c"]
: no substitution exists to transform the pattern
into the expression by substituting the wildcards.
Matching an Expression to a Pattern
To check if an expression matches a pattern, use the
_expression_.match(_pattern_)
method.
If there is no match, the method returns null
.
If there is a match, a Substitution
object literal with
keys corresponding to the matching named wildcards is returned.
If no named wildcards are used and there is a match, an empty object literal is returned.
For convenience, the pattern argument can be an unboxed MathJSON expression.
Commutativity
The commutativity of functions is taken into account when matching patterns.
Exact Matching
By default, the expr.match()
method will match some variants of the same
expression, for example x+_a
and x
are considered to match (with the
substitution {_a : 0}
).
To prevent the matching of variants, set the exact
property to true
.
The variants can be applied to the whole expression or to sub-expressions.
Recursive Matching
By default, the expr.match()
method does not consider sub-expressions:
it is not recursive.
To match sub-expressions recursively, set the recursive
property to
true
.
Repeated Named Wildcards
If a named wildcard is referenced multiple times in a pattern, all its values must match.
Capturing the Head of Functions
Wildcards can be used to capture the head of functions:
Substitution
The return value of the expr.match()
function is a Substitution
object: a
mapping from wildcards to expressions.
If there is no match, expr.match()
returns null
.
To apply a substitution to a pattern, and therefore recover the expression
it was derived from, use the subs()
function.
Applying Rewrite Rules
A rewrite rule is an object with three properties:
match
: a matching patternreplace
: a substitution patterncondition
: an optional condition predicate
To apply a set of rules to an expression, call the expr.replace()
function.
Each rule in the ruleset is applied to the expression in turn. If a rule matches, the expression is replaced by the substitution pattern of the rule.
The expr.replace()
function continues applying all the rules in the ruleset
until no rules are applicable.
If expr
is not canonical, the result of the replace operation is not
canonical either.
Simplifying an Expression
The expr.simplify()
function applies a collection of built-in rewrite rules.
You can define your own rules and apply them using expr.replace()
.
Substituting Symbols
If a pattern does not contain any named wildcards and only symbols, the
expr.subs()
function can be used to replace all occurrences of matching symbols.