6.8.11.4 Conditional Syntax Rules

It is possible to attach a condition to a syntax rule. For example, the rules

foo ( # ) := ifoo(#1) :: integer(#1)
foo ( # ) := gfoo(#1)

will parse ‘foo(3)’ as ‘ifoo(3)’, but will parse ‘foo(3.5)’ and ‘foo(x)’ as calls to gfoo. Any number of conditions may be attached; all must be true for the rule to succeed. A condition is “true” if it evaluates to a nonzero number. See Logical Operations, for a list of Calc functions like integer that perform logical tests.

The exact sequence of events is as follows: When Calc tries a rule, it first matches the pattern as usual. It then substitutes ‘#1’, ‘#2’, etc., in the conditions, if any. Next, the conditions are simplified and evaluated in order from left to right, using the algebraic simplifications (see Simplifying Formulas). Each result is true if it is a nonzero number, or an expression that can be proven to be nonzero (see Declarations). If the results of all conditions are true, the expression (such as ‘ifoo(#1)’) has its ‘#’s substituted, and that is the result of the parse. If the result of any condition is false, Calc goes on to try the next rule in the syntax table.

Syntax rules also support let conditions, which operate in exactly the same way as they do in algebraic rewrite rules. See Other Features of Rewrite Rules, for details. A let condition is always true, but as a side effect it defines a variable which can be used in later conditions, and also in the expression after the ‘:=’ sign:

foo ( # ) := hifoo(x) :: let(x := #1 + 0.5) :: dnumint(x)

The dnumint function tests if a value is numerically an integer, i.e., either a true integer or an integer-valued float. This rule will parse foo with a half-integer argument, like ‘foo(3.5)’, to a call like ‘hifoo(4.)’.

The lefthand side of a syntax rule let must be a simple variable, not the arbitrary pattern that is allowed in rewrite rules.

The matches function is also treated specially in syntax rule conditions (again, in the same way as in rewrite rules). See Matching Commands. If the matching pattern contains meta-variables, then those meta-variables may be used in later conditions and in the result expression. The arguments to matches are not evaluated in this situation.

sum ( # , # ) := sum(#1,a,b,c) :: matches(#2, a=[b..c])

This is another way to implement the Maple mode sum notation. In this approach, we allow ‘#2’ to equal the whole expression ‘i=1..10’. Then, we use matches to break it apart into its components. If the expression turns out not to match the pattern, the syntax rule will fail. Note that Z S always uses Calc’s Normal language mode for editing expressions in syntax rules, so we must use regular Calc notation for the interval ‘[b..c]’ that will correspond to the Maple mode interval ‘1..10’.