• No results found

An example of a simple pattern-defined function Clear @ f D ;Clear@fD;

f@x_D:=x ^ 2;

8f@2D, f@"word"D, f@NewtonD<

94, word2, Newton2=

In this example, the result is as shown because the definition of the function < f > is really just a substitu -tion rule f[anything] -> (anything)^2.

Ÿ 1.2.3 Functions are really rules : DownValues command.

To see the internal form of this rule - how it is stored in the rule base - one can use the built-in DownVal-ues command. With its help we see:

DownValues@fD

9HoldPattern@f@x_DD ¦x2=

We will talk later about the meaning of the HoldPattern function. The pattern x_ is the most simple pat-tern. There can be more complex patterns, both syntactically and also because patterns may have condi-tions attached to them, which ensure that the pattern will match only if the condition is satisfied (conditional patterns). We will cover them in detail later.

Ÿ 1.2.4 Example of a function based on a restricted pattern

Now let us give an example: we will restrict our function <f> to operate only on integers.

Clear@fD;

f@x_IntegerD:=x ^ 2;

8f@2D, f@PiD, f@"word"D, f@NewtonD<

84, f@ΠD, f@wordD, f@NewtonD<

In this case, we introduced a more complex pattern x_Integer.

Ÿ 1.2.5 A bit about evaluation

On this example we see that if there is no rule whose pattern (left hand side of the rule) matches a given expression, Mathematica returns the expression unchanged. This is at the heart of its evaluation method:

to any entered expression, all rules which are in the global rule base at the moment of evaluation, are applied iteratively. Whenever some rule applies, an expression is rewritten and the process starts over.

At some point, the expression becomes such that no rule can be applied to it, and this expression is the result. Since the rule base contains both system and user-defined rules (with the latter having higher priority), it gives great flexibility in manipulation of expressions.

Ÿ 1.2.6 Patterns allow for multiple definitions of the same function

As another starting example, let us define a function which is linear on even numbers, quadratic on odd numbers and is a Sin function for all other inputs:

Clear@fD;

f@x_ ? EvenQD:=x;

f@x_ ? OddQD:=x ^ 2;

f@x_D:=Sin@xD;

Here is an example of its execution on various inputs :

8f@1D, f@2D, f@3D, f@4D, f@32D, f@NewtonD, f@PiD<

:1, 2, 9, 4, SinB3

2F, Sin@NewtonD, 0>

For the record, built - in functions OddQ and EvenQ are predicates which return True if the number is odd (even) and False otherwise :

8EvenQ@2D, EvenQ@3D, OddQ@2D, OddQ@3D<

8True, False, False, True<

If nothing is known about the object, they give False : 8EvenQ@NewtonD, OddQ@NewtonD<

8False, False<

Ÿ 1.2.7 Non - commutativity of rules substitution

Let us look at the last of the 3 definitions of < f > in the above example. It implies that any input object has to be replaced by its Sine. Naively, this would mean that we should have obtained Sine-s of all our expressions, but this did not happen. The point is that the sequential rule application is non-commutative:

first of all, the way rules are applied is such that once the first rule that applies is found, only this rule is applied, and other possibly matching rules are not tried on a given (sub)expression, in a single "run" of the rule application. Second, if several rules match an expression, the first applied rule rewrites it so that (some) of other rules don’t match it any more. Therefore, the result depends on the order in which the rules are applied. Mathematica applies rules to expressions sequentially. Since the rule with the Sine function was defined last, it should mean that it has a chance to apply only to inputs whose form did not match patterns in the first two rules.

Ÿ 1.2.8 Automatic rule reordering

What is less trivial is that in this example we would get similar behavior even if we defined this rule first:

Clear@fD;

f@x_D:=Sin@xD; f@x_ ? EvenQD:=x;

f@x_ ? OddQD:=x ^ 2;

8f@1D, f@2D, f@3D, f@4D, f@32D, f@NewtonD<

:1, 2, 9, 4, SinB3

2F, Sin@NewtonD>

To see the order in which the rules are kept, we again use DownValues : DownValues@fD

9HoldPattern@f@x_ ? EvenQDD ¦x,

HoldPattern@f@x_ ? OddQDD ¦x2, HoldPattern@f@x_DD ¦Sin@xD=

We see that the rule with Sine again is at the end, despite having been defined first. The reason is that Mathematica pattern-matching engine has a built-in rule analyzer which sorts the rules such that more general rules come after more specific ones, when it can determine it. This is not always possible to do automatically (and not always possible to unambiguously do at all), so in general the programmer should take care of it. But in practice, it is seldom needed to manipulate the rules by hand.

We see that the rule with Sine again is at the end, despite having been defined first. The reason is that Mathematica pattern-matching engine has a built-in rule analyzer which sorts the rules such that more general rules come after more specific ones, when it can determine it. This is not always possible to do automatically (and not always possible to unambiguously do at all), so in general the programmer should take care of it. But in practice, it is seldom needed to manipulate the rules by hand.

Ÿ 1.3 Third principle: expression evaluation

The last example brings us to the third principle: the principle of expression evaluation and the rewrite rules (global rule base). It tells the following: when Mathematica encounters an arbitrary expression, it checks its global base of rewrite rules for rule(s) which correspond to a given expression (or, it is said, match the expression). A typical rewrite rule looks like object1 -> object2. If such a rule is found, for expression or any of the subexpressions (actually, normally in reverse order), the (sub) expression is rewritten, and the process starts over. This process goes on until no further rule in the global rule base is found which matches the expression or any of its parts. When the expression stops changing, it is returned as the answer. Please bear in mind that the picture just described is a great oversimplification, and the real evaluation process is much more subtle, although the main idea is this.

The global rule base contains both rules built in the kernel and rules defined by the user. User-defined rules usually take precedence over the system rules, which makes it possible to redefine the behavior of almost any built-in function if necessary. In fact, all assignments to all variables and all function defini-tions are stored as some type of global rules, in the rule base. In this sense, there is no fundamental differ-ence between functions and variables (although there are technical differdiffer-ences).

As a result of this behavior, we get for instance such result:

FullForm@Sin@Pi +PiDD

0

The reason is that inside the kernel there are rules like Plus[x,x]->2 x, Sin[2*Pi]->0, and because the evaluation process by default starts with the innermost sub-expressions (leaves), i.e., from inside out, it produces 0 before the FullForm has any chance to "look" at the expression. The internal evaluation dynam-ics can be monitored with the Trace command:

Trace@FullForm@Sin@Pi +PiDDD 888Π +Π, 2Π<, Sin@2ΠD, 0<,0<

Ÿ Summary

To summarize, we have described briefly the main principles of Mathematica and along the way gave examples of use of the following built-in functions: AtomQ, Head, FullForm, TreeForm, Level, Plus, Times, Trace, DownValues, OddQ, EvenQ.