dijkstra.icn: Procedures for Dijkstra's "Discipline" control structures

procedure do_od:           Dijkstra's do_od construct
procedure if_fi:           Dijkstra's if_fi construct

link dijkstra
December 9, 2003; Frank J. Lhota
This file is in the public domain.

The procedures do_od and if_fi implement the "do ... od" and "if ... fi"
control structures used in the book "A Discipline of Programming" by
Edsger W. Dijkstra. This book uses a programming language designed to
delay implementation details, such as the order in which tests are
performed.

Dijkstra's programming language uses two non-ASCII characters, a box and
a right arrow. In the following discussion, the box and right arrow
characters are represented as "[]" and "->" respectively.

The "if ... fi" control structure is similar to multi-branch "if" statements
found in many languages, including the Bourne shell (i.e. the
"if / elif / fi" construct). The major difference is that in Dijkstra's
notation, there is no specified order in which the "if / elif" tests are
performed. The "if ... fi" structure has the form

      if
            Guard1 -> List1
         [] Guard2 -> List2
         [] Guard3 -> List3
         ...
         [] GuardN -> ListN
      fi

where

     Guard1, Guard2, Guard3 ... GuardN are boolean expressions, and
     List1, List2, List3 ... ListN are lists of statements.

When this "if ... fi" statement is performed, the guard expressions are
evaluated, in some order not specified by the language, until one of the
guard expressions evaluates to true. Once a true guard is found, the list
of statements following the guard is evaluated.  It is a fatal error
for none of the guards in an "if ... fi" statement to be true.

The "do ... od" control is a "while" loop structure, but with multiple
loop conditions, in style similar to "if ... fi". The form of a Dijkstra
"do" statement is

      do
            Guard1 -> List1
         [] Guard2 -> List2
         [] Guard3 -> List3
         ...
         [] GuardN -> ListN
      od

where

     Guard1, Guard2, Guard3 ... GuardN are boolean expressions, and
     List1, List2, List3 ... ListN are lists of statements.

To perform this "do ... od" statement, the guard expressions are
evaluated, in some order not specified by the language, until either a
guard evaluates to true, or all guards have been evaluated as false.

- If all the guards are false, we exit the loop.
- If a guard evaluates to true, then the list of statements following this
  guard is performed, and then we loop back to perform this "do ... od"
  statement again.

The procedures if_fi{} and do_od{} implement Dijkstra's "if ... fi" and
"do ... od" control structures respectively. In keeping with Icon
conventions, the guard expressions are arbitrary Icon expressions. A guard
is considered to be true precisely when it succeeds. Similarly, a statement
list can be represented by a single Icon expression. The Icon call

      if_fi{
          Guard1, List1,
          Guard2, List2,
          ...
          GuardN, ListN
         }

suspends with each result produced by the expression following the true
guard. If none of the guards succeed, runerr() is called with an appropriate
message.

Similarly, the Icon call

      do_od{
          Guard1, List1,
          Guard2, List2,
          ...
          GuardN, ListN
         }

parallels the "do ... od" statement. As long as at least one guard
succeeds, another iteration is performed. When all guards fail, we exit
the loop and do_od fails.

The test section of this file includes a guarded command implementation of
Euclid's algorithm for calculating the greatest common denominator. Unlike
most implementations of Euclid's algorithm, this version handles its
parameters in a completely symmetrical fashion.

Source code | Program Library Page | Icon Home Page