Special Programming Constructs

More Patterns

We have already seen several possibilities in the introductory sections how to specify patterns in the Mathematica programming language. We will now show some more details on patterns.

Variables vs. Constants

In a pattern a symbol alone stands for a constant with that name.

ClearAll[f];
f[a,b]:=a+b-3

f[a,b]

f[4,4]

a=3;

f[a,b]

SetAttributes[f,HoldAll]

f[a,b]

In this example, f is only defined for constant parameters named "a" and "b", respectively. Attaching an underscore ("_") to a symbol turns it into a variable, i.e. something that concrete values can be substituted for.

ClearAll[f];
f[x_,y_]:=x+y-3

f[4,4]

f[a,b]

Interpret the patttern x_ as follows: "Something that can be addressed as x". Precisely, it is the value that is substituted during pattern matching that we address as x. The name for this pattern is, in fact, optional.

SecondElement[{_,s_}]:=s

SecondElement[{a,b}]

Named Pattens

A parameter of the form name:pattern allows to refer to the entire expression matched by pattern by name.

Diff[f:((a_)^( x_)),x_]:=f Log[a]

Diff[((a_)^( x_)),x_]:=(a^x) Log[a]

Diff[f_,x_]:=Module[{a=Base[f]},f Log[a]]

Diff[(2^x),x]

Of course, we could also live without this feature, but it is convenient and it makes programs shorter. Note that we could always compose the matched expression on the right–hand side of our program:

Diff[((a_)^( x_)),x_]:=(a^x) Log[a]

Restricted Patterns

A pattern _ matches any expression. There are several possibilities to restrict matching to only certain categories of expressions. A pattern _h matches only expressions with head h.

Clear[f];
Attributes[f]={HoldAll};
f[x:((a_Integer)^(n_))]:=(x^2)+n a;
f[x:((a_Real)^(n_))]:=x+n a;

f[(3^2)]

f[(3.0^2)]

Pattern matching is mainly based on syntax, i.e. patterns describe mostly the syntactical structure of an expression. However, if we want to develop a pattern for "a pair of successive integers", then we cannot describe this on a purely syntactic basis.

MatchQ[{5,6},{n_,n_+1}]

The point is that 6 does not have the syntactical structure 5+1. But:

MatchQ[{a,a+1},{n_,n_+1}]

The Mathematica pattern language provides the possibility to express also non–syntactic properties in patterns by allowing arbitrary conditions to be tested on patterns.

MatchQ[{5,6},{n_,m_}/;m==n+1]

In expressions like above be careful to place the condition at a position where all the variables have values assigned during the pattern matching process. Attaching the condition only to m would not work because at this position the pattern matcher "does not see" the value matched for n.

MatchQ[{5,6},{n_,m_/;m==n+1}]

MatchQ[{5,n+1},{n_,m_/;m==n+1}]

Clear[f];
f[x_/;Positive[x]]:=1;
f[x_?Negative]:=-1;

??f

Plot[f[x],{x,-5,5}]

f[0]

f[_]:=0

f[-1]
f[0]
f[1]

Note, that a condition need not be attached to the left–hand side of a definition (the pattern), it can also go with the right–hand side of a definition.

ClearAll[f]
f[l_]:=(Sqrt[l])/;VectorQ[l,NonNegative]

f[{16,0,30}]

f[{-16,0,30}]

Sequences

There are also patterns for sequences of expressions. The pattern __ (2 underscores) matches a sequence of 1 or more expressions, the pattern ___ (3 underscores) matches 0 or more expressions. Note that it does not match the list of expressions, it only matches the sequence!

Double[{f_,r___}]:=Prepend[Double[{r}],2 f]
Double[{}]:={}

Double[{2,3,4}]//Trace

Clear[Double]
Double[{f_,r__}]:=Prepend[Double[{r}],2 f]
Double[{x_}]:={2 x}

Double[{2,3,4}]//Trace

The patterns __h and ___h match sequences, where each of the elements has head h.

MatchQ[{1,2,3},{__Integer}]

MatchQ[{1,2,3,π},{__Integer}]

Repeated Patterns

Similar to sequences, we can specify repetitions of patterns:

{1,{3.5,2},{3,4},{}}/.{_Integer..}->"INT"

{1,{3.5,2},{3,4},{}}/.{_Integer...}->"INT"

Optional Parameters

ClearAll[Rotate,ComplexToList];
ComplexToList[z_]:={Re[z],Im[z]};
Rotate[{x_,y_},angle_,dir_:1]:=ComplexToList[N[(x+I y) (Cos[dir angle]+I Sin[dir angle])]]

Rotate[{x,y},(π/5)]

Rotate[{x,y},ϕ]

Rotate[{x,y},ϕ,-1]

Rotate[{1,0},(π/5)]

Rotate[{1,0},(π/5),-1]

For certain expressions there are built–in default values for pattern matching.

Diff[(((x_))^(n_.)),x_]:=n (x^(n-1))

Diff[(y^3),y]

Diff[y,y]

Diff1[(((x_))^(n_)),x_]:=n (x^(n-1))

Diff1[y,y]

x_+y_.

If a pattern of the form _. occurs as a parameter in an expression with head h, then Default[h] specifies the default value for this parameter. Default[h,i] specifies the default value for the parameter at the i'th position.

??Plus

??Power

??Times

Alternatives

A pattern of the form p1|p2 matches if at least one of the patterns p1 or p2 matches. Of course, an alternative can consist of even more than 2 patterns.

ClearAll[Rot,ComplexToList];

ComplexToList[z_]:={Re[z],Im[z]};

Rot[{x_,y_},angle_,dir:1|-1:1]:=ComplexToList[N[(x+I y) (Cos[dir angle]+I Sin[dir angle])]]

?Rot

Rot[{1,0},(π/5)]

Rot[{1,0},(π/5),1]

Rot[{1,0},(π/5),-1]

Rot[{1,0},(π/5),2]

Program Options with Named Parameters

Default values for optional parameters can be specified using the pattern p:v, see above. Ambiguities may arise if more than one optional parameter is specified. In order to avoid these ambiguities it is advisable to use named parameters in these cases. In Mathematica we can use transformation rules to implement the concept of named parameters. Suppose we want to implement a program that rotates a given point with a certain angle about the origin, see above. Optional parameters for this program are the direction and the unit for the angle (degree or radians).
Mathematica provides a standard function Options that returns the available optional parameters for a given function. Optional parameters are represented as transformation rules name->value, where name is the name of the parameter and value is its default value.

ClearAll[MyRotate,ComplexToList];
ComplexToList[z_]:={Re[z],Im[z]};

Options[MyRotate]={Direction->"CCW",Unit->Degree}

??MyRotate

??Solve

There is a standard way to process optional parameters given in this form. Study the program below to see how the values for optional parameters are turned into local variables in the program.

MyRotate[{x_,y_},α_,opts___?OptionQ]:=
Module[{dir,u,un},
{dir,un}={Direction,Unit}/.{opts}/.Options[MyRotate];
u=Switch[un,Degree,π/180,Rad,1,_,0];
ComplexToList[N[(x+I y) (Cos[α u]+I Sin[Switch[dir,"CCW",1,"CW",-1,_,0]*α*u])]]]

Note, that when you ask for information about Rotate, its optional parameters are always listed.

?MyRotate

MyRotate[{1,0},(π/5),Unit->Rad]

MyRotate[{1,0},(π/5),Unit->Rad,Direction->"CW"]

MyRotate[{1,0},(π/5),Direction->"CW",Unit->Rad]

MyRotate[{1,0},36,Direction->"CW"]

Non–standard Return Values

Break, Continue, and Return

For procedural programming constructs (loops) there are the well–known constructs for special program behavior within loops. Break exits a loop and Continue immediately proceeds to the next iteration. Return returns a value from an arbitrary point in the program. This is useful only if used from within a program, if the program should return from the end of the program then an explicit Return is not necessary, since the value of the last statement is automatically the return value of the entire program.
There is one particular thing to be mentioned about Return in connection with a Do–loop: If Return occurs inside Do, then it only returns a value from the loop, it does not exit the enclosing function.

Catch and Throw

Catch and Throw allow to return values from deeply nested function calls. Throw returns a value directly to the enclosing Catch, regardless of the hierarchy of calling functions. This can be useful e.g. for terminating iterations initiated by Nest, FixedPoint, or similar functions. Details see in the manual.

FixedPoint[Function[x,If[x==10,Throw[x+45]];x+1],1]

Catch[FixedPoint[Function[x,If[x==10,Throw[x+45]];x+1],1]]

Reap and Sow

Reap and Sow allow to return intermediate values from an evaluation together with the return value. Details see in the manual.