Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 56 additions & 29 deletions mathics/builtin/patterns/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,48 +19,75 @@


class Optional(InfixOperator, PatternObject):
"""

<url>:WMA link:https://reference.wolfram.com/language/ref/Optional.html</url>
"""<url>:WMA link:https://reference.wolfram.com/language/ref/Optional.html</url>

<dl>
<dt>'Optional'[$pattern$, $default$]
<dt>'$pattern$ : $default$'
<dd>is a pattern which matches $pattern$, which if omitted
should be replaced by $default$.
<dd>is a pattern matching $pattern$; when $pattern$ is omitted, \
$default$ is substituted for $pattern$.
</dl>

Optional is used to specify optional arguments in function signatures.

Set up a default value of 1 for the pattern 'y_' in function 'f':

>> f[x_, y_:1] := {x, y}
>> f[1, 2]
= {1, 2}

Above, we put no spaces before or after ':', but they can be added. So:

>> f[x_, y_: 1] := {x, y}

is the same as the above.

When we specify a value for the 'y' parameter, it has the value provided:
>> f[a, 2]
= {a, 2}

But if the 'y' parameter is missing, we replace the parameter \
using the default given in the delayed assignment above:

>> f[a]
= {a, 1}

Note that '$symb$ : $pattern$' represents a 'Pattern' object. However, there is no \
disambiguity, since $symb$ has to be a symbol in this case.
Both 'Optional' and <url>:Pattern:
/doc/reference-of-built-in-symbols/rules-and-patterns/composite-patterns/pattern/</url> \
use ':' as their operator symbol. And both operators are used to represent a pattern.

The way to disambiguate which of the two is used is by the first or left operand. When \
this is a $symbol$, like 'y', the ':' operator indicates a 'Pattern':

>> x:_ // FullForm
= Pattern[x, Blank[]]
>> _:d // FullForm
= Optional[Blank[], d]
>> x:_+y_:d // FullForm
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example does not seem motivated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the motivation is to show the order of interpretation: the second colon is interpreted first, to build the inner Optional expression, and then the first one is interpreted as a named Pattern.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I'll add this example back, adding this explanation.

Copy link
Member Author

@rocky rocky Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the motivation is to show the order of interpretation: the second colon is interpreted first, to build the inner Optional expression, and then the first one is interpreted as a named Pattern.

Hmm... It looks like we may have the wrong Precedence indicated for Pattern. We give Pattern value 670 while it is 150 in WMA. In both WMA and Mathics3, though, Optional is 140. So the behavior is natural.in WMA while in Mathics3, it goes contrary to what is specified.

Is this something we specifically hacked around? and would get wrong were we to follow the usual precedence rules?

Edit what we have would give the same behavior. But, I wonder if there is a reason not to use the same value 150.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at the precedence issue, and it is tagged with the right value in mathics_scanner, but Pattern is not tagged as an operator in mathics-core, and if that's changed, other things break. 670 is the magic number that's given when we can't find a precedence value tagged.

Sigh.

>> y : 1 // FullForm
= Pattern[y, 1]

In contrast, we have a <i>pattern</i> to the left of the colon, like 'y_' we have an 'Optional' expression:

>> y_ : 1 // FullForm
= Optional[Pattern[y, Blank[]], 1]

The special form 'y_.' is equivalent to 'Optional[y_]':

>> FullForm[y_.]
= Optional[Pattern[y, Blank[]]]

In this situation, when the is 'y' parameter omitted, the value comes from <url>\
:Default:/doc/reference-of-built-in-symbols/options-management/default/</url>:

>> Default[g] = 4
= 4

>> g[x_, y_.] := {x, y}

>> g[a]
= {a, 4}

Note that the 'Optional' operator binds more tightly than the \
'Pattern'. Keep this in mind when there is more than one colon, \
juxtaposed, each representing different operators:

>> x : _+y_ : d // FullForm
= Pattern[x, Plus[Blank[], Optional[Pattern[y, Blank[]], d]]]

's_.' is equivalent to 'Optional[s_]' and represents an optional parameter which, if omitted, \
gets its value from 'Default'.
>> FullForm[s_.]
= Optional[Pattern[s, Blank[]]]

'InputForm' shows it in its 'Infix' or 'Postfix' form depending on the \
number of parameters:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InputForm, by default, uses infix for equations. I do not understand from the example where the number of parameters is coming into play. And I do not see where postifx notation is selected.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no Infix form with just one argument...

Copy link
Member Author

@rocky rocky Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, this degenerate case is defined on Infix:

In[2]:= Infix[{1}, "+"]
Out[2]= 1

But the larger and more important point is: what does this Infix and Postfix stuff have to do with the examples?

>> InputForm[s_:a+b^2]
= s_ : a + b^2
Following WMA conventions,
>> InputForm[Optional[s__]]
= (s__.)
>> Default[h, k_] := k
>> h[a] /. h[x_, y_.] -> {x, y}
= {a, 2}
"""

arg_counts = [1, 2]
Expand Down
Loading