prev up next

4) Selection statements

Here is an Aldwych single-rule procedure for calculating the factorial of an integer:

#fact(n) <== 
   ?a\eq(n,0)
   :>1;
   :>n*fact(n-1);
The expression fact(n) here has the value of the factorial of n. In part 3, we suggested the following procedure for square:
#square(m) <==> m*m;
In fact the <==> here breaks into three symbols. The first is < which is attached to a procedure heading following the closing bracket, and indicates the procedure returns a non-object value. The alternative is ~ for a procedure which returns an object, and that includes the object descriptors of part 2. It is also possible to have procedures which do not have any output, which we shall see later. The == symbol indicates a single-rule procedure. This means that a call to that procedure rewrites straight away to the body with the appropriate substitution of arguments for parameter variables; there is no waiting for arguments to be bound before the rewriting may take place. The final > in <==> indicates a return statement. >exp where exp is any expression returns the expression as the return value of a single-rule procedure, or the return value of a message in an object descriptor. If a procedure returns an object, <=exp is used as the return statement instead. Following the single-assignment principle, there may be only one value return or only one object return in a simple rule rhs (later we shall see cases where there is both a value return and an object return).

The factorial procedure above shows a compound rhs. A rhs may consist of a number of statements (in this factorial example the number is zero) followed by a selection statement which takes the form ?<boolean expression>:<rhs>:<rhs>. If the rule requires a return and none of the statements before the selection statement is one, then both the subsidiary rhss in the selection statement must have one. The subsidiary rhss may themselves contains selection statements, enabling more complex selection statements to be constructed.

Aldwych does not use infix boolean operators in rhss, hence the boolean expression above takes the form a\eq(n,0). This uses the procedure eq from Aldwych's built-in library a. Unlike aio the library a is not mentioned separately when the KLIC file is compiled. eq is an equality test on integers and strings. a also contains inequality tests ne, gt, ge, lt, and le, meaning "not equal", "greater than", "greater than or equal", "less than" and "less than or equal" respectively. With strings the ordering used is alphabetically. Compound boolean expressions may be built up using a , symbol to mean "and" and a ; symbol to mean "or". These symbols have these meanings only in the context of a boolean expression in a selection statement, and the usual rule that :and" has higher precedence than "or" is kept.

Using selection statements, we can now write a version of time which gives the correct string when the number of minutes past the hour is less than ten:

#time(-hours,-mins)~
<(totmins<-hours*60+mins)
{
 clone~  |>time(0,totmins);
 hours-  |>totmins/60;
 minutes-|>totmins//60;
 add(n)  | totmins+=n;
 sub(n)  | totmins-=n;
 toString-| ?a\eq(totmins//60,0)
              :>"">+totmins/60>":00";
              :?a\lt(totmins//60,10)
                 :>"">+totmins/60>":0">+totmins//60;
                 :>"">+totmins/60>":">+totmins//60
}
This is not very satisfactory, however, due to the need to recalculate the hours figure up to three times. A better form of the toString rule calculates the hours and minutes values first and passes them in as local variables to the selection statement:
toString-| <(hrs<-totmins/60,mins<-totmins//60)
           ?a\eq(mins,0)
             :>"">+hrs>":00";
           :?a\lt(mins,10)
             :>"">+hrs>":0">+mins;
             :>"">+hrs>":">+mins
The layout has also been tidied up to indicate an "else if" structure.

Although local variables may be freely shared in the statements on a rhs, if they are to be used in the selection statement which ends it, they have to be passed in, in a list starting with <(, ending with ) and separated by commas. In the above, the local variables are given values and passed at the same time. An alternative where the values are given separately is:

toString-| hrs<-totmins/60,mins<-totmins//60,
           <(hrs,mins)
           ?a\eq(mins,0)
             :>"">+hrs>":00";
           :?a\lt(mins,10)
             :>"">+hrs>":0">+mins;
             :>"">+hrs>":">+mins

Selection rules

An alternative to using selection statements is to use selection rules. Here is a version of the factorial procedure which uses selection in rules:
#fact(n)<
{
 n=0 ||>1;
 n>0 ||>n*fact(n-1);
}
Note the lhs and rhs of the rules are separated by double bars rather than single bars as in object descriptors as described in part 2. The lhs consists of conditions on the arguments to the procedure, which do use infix operators. The infix operators which may be used are >, >=, <, <=, =, ==, # and \=. The symbol = is used with its left hand argument a variable and its right-hand argument a number or a string, whereas == is used to compare two variables for equality. A similar distinction is made for inequality between # and \=, with the latter the one to compare two variables.

As a procedure call returns a value, each rule in it return a value, using the > form previously described for returning values for object messages. For procedures that return objects, the <= return form is used.

A procedure call will evaluate using one of its rules, once it has done so there is no returning and trying other rules (this is mentioned because the logic programming language Prolog has as a major feature such "backtracking"). Since computation is concurrent in Aldwych, a procedure call may be set up before all its arguments variables have been written to. A comparison operator requires both arguments to be written to, and will suspend evaluation until both have been written to. A procedure call will evaluate using one of its rules if all the variables that rule's lhs requires are written to and its tests evaluate to true, even if other rules are suspended.

A rule statement may occur at the end of a rule rhs. In an object descriptor, it works like a call to a procedure which takes the arguments of that object, plus any arguments in the message on the lhs of the rule, plus any additional local arguments passed in as with selection statements. It returns a reply for the message. For example, the rule for toString in time could be written:

toString-| <(hrs<-totmins/60,mins<-totmins//60)
            {
             mins=0 ||>"">+hrs>":00";
             mins>0,mins<10 ||>"">+hrs>":0">+mins;
             mins>=10 ||>"">+hrs>":">+mins;
            }
Here, the second rule in the inner rule set shows that more than one comparison may occur on the lhs of a rule. All comparisons on the lhs must succeed for the rule to be applicable, so the commas between them could be considered as meaning "and". However, unlike selection statements there is no "or". Also note that whereas conditional expressions in selection statements contain procedure calls and not direct comparisons, in rule statements it is the other way round - procedure calls may not be used on the lhs of a rule.

A : symbol immediately after a rule in a set of selection rules means "otherwise". This can be used to simplify rules. Rules following an otherwise are tried only after the lhss all those of all those before it have failed. Even if a rule before an otherwise is suspended, rules after it will not be attempted until the suspension is ended and the lhs failed. More than one otherwise may be used in a set of rules. So the factorial procedure could be written:

#fact(n)<
{
 n=0 ||>1;
 :   ||>n*fact(n-1);
}
and the rule for the toString method of time could be written:
toString-| <(hrs<-totmins/60,mins<-totmins//60)
            {
             mins=0  ||>"">+hrs>":00";
             :
             mins<10 ||>"">+hrs>":0">+mins;
             :
                     ||>"">+hrs>":">+mins;
            }
The blank lhs of the final inner rule here means it always applies if rule consideration reaches this point after the previous otherwises.

Apart from "otherwise", no ordering is assumed on rules. If more than one rule is applicable, any of the applicable rules could be chosen for use, which one is indeterminate.

prev up next