The ABC Programmer's Handbook by Leo Geurts, Lambert Meertens, and Steven Pemberton

A Quick Look at ABC

[An Example] [Types [ Numbers] [ Texts] [ Compounds] [ Lists] [ Tables] [ Generic operations]] [User-defined Commands and Functions] [Names and Locations] [Control Commands] [Random] [Tests] [Input/Output] [Refinements]

An Example

```HOW TO PRINT CELSIUS FROM a TO b:
PUT a, b IN lo, hi
IF lo > hi:
PUT hi, lo IN lo, hi \Swap hi and lo
FOR f IN {lo..hi}:
PUT (f-32)*5/9 IN c
WRITE f, "Fahrenheit =", 2 round c, "Celsius" /```

Once this piece of ABC (the definition of a command `PRINT CELSIUS` for listing temperatures in degrees Fahrenheit converted to degrees Celsius) has been entered, you can give this command:

`PRINT CELSIUS FROM 40 TO 45`

You then get the following on your screen (we use a slanting font for output from ABC):

```40 Fahrenheit = 4.44 Celsius
41 Fahrenheit = 5.00 Celsius
42 Fahrenheit = 5.56 Celsius
43 Fahrenheit = 6.11 Celsius
44 Fahrenheit = 6.67 Celsius
45 Fahrenheit = 7.22 Celsius```

The text of this how-to is straightforward:

• The top line shows the name of the command, and the template parameters `a` and `b`, which are in lower case.
• `PUT` has an expression to the left of `IN`, and an address to the right. The expression is evaluated to give a value, and the address to give a location. The value is then put in the location. As we shall see later, this multiple `PUT` command in fact puts one compound value in one compound location. The second `PUT` command swaps the values of `lo` and `hi`.
• A comment begins with a back-slash character '`\`', and continues to the end of the line. A comment can come after a command, or occur on a line by itself.
• A control command, such as `IF` or `FOR`, controls the indented commands following the corresponding colon. Thus, the user need not bother about pairs of `BEGIN` and `END` or other delimiters for grouping commands. For the same reason, the whole body of the how-to has been indented. If there is only one controlled command, the whole construction may be displayed on a single line:
`IF a < 0: PUT -a IN a`
• The `FOR` command traverses the list of numbers which starts at `lo` and ends with `hi`.
• The `round` function in the `WRITE` command rounds its right operand to 2 digits after the decimal point, as indicated by its left operand.
• The `/` at the end of the `WRITE` command specifies transition to a new line.

In the ABC system a friendly editor takes care of the tedious aspects of typing the program, such as indentation and other layout matters, capitals, keywords such as `PUT` and `WRITE`, etc. This is explained in chapter 3, Using ABC.

Types

The power of ABC is largely due to its carefully designed system of data types and associated operations. There are two basic types - numbers and texts and three structures creating new types from existing ones - compounds lists and tables

Numbers

Integers, that is, whole numbers, in ABC are unusual in that there is no restriction on length. Furthermore, integers are just a special case of exact i.e. rational, numbers (integral fractions). For example, `1.25` is an exact number. Calculations on exact numbers with the operators `+`, `-`, `*` (multiplication) and `/` (division), give exact results.

In addition to exact numbers, there are approximate (floating point) numbers. The operator `~` is used for conversion to an approximate number: `~22/7` does not return an exact, but an approximate number. Calculations with the mathematical functions like `root`, `sin`, and `log`, return approximate numbers. The function `exactly` converts an approximate number to exact.

Mixed arithmetic is allowed, as in `2*sin(x-1)`.

Operations: Examples:
plain arithmetic `+x`, `x+y`, `-x`, `x-y`, `x*y`, `x/y`
to the power `3**2 = 9`
round upwards `ceiling 3.68 = 4`
round downwards `floor 3.68 = 3`
round to nearest integer `round 3.68 = 4`
round to `n` digits after decimal point `1 round 3.68 = 3.7`
sign `sign 3.68 = 1`
absolute value `abs(-3.68) = 3.68`
square root `root 2 = ~1.4142135623731`
`n` -th root `3 root 2 = ~1.2599210498949`
remainder after division `27 mod 10 = 7`
numerator of exact number `*/ 1.25 = 5`
denominator of exact number `/* 1.25 = 4`
natural logarithm `log 10 = ~2.302585092994`
logarithm to base `b` `2 log 8 = ~3`
exponential function `exp 1 = ~2.718281828459`
trigonometric functions in radians `sin x,` `cos x,` `tan x,` `arctan x,` `angle(x,y)`
trigonometric functions in degrees ```360 sin x, 360 cos x, 360 tan x, 360 arctan x, 360 angle (x, y)```
distance from origin `radius(x, y)`

The functions `*/` and `/*` yield the numerator and the denominator of an exact number. For this purpose, fractions are automatically reduced to lowest terms; so `1.25 = 125/100` is reduced to `5/4`. Again, there is no restriction on the lengths of the numerator and denominator. The following definition for the greatest-common-divisor function of two exact positive numbers uses this property (as long as `a` and `b` are not 0):

`HOW TO RETURN gcd(a, b): RETURN a / */(a/b)`

Texts

`"Merry Christmas"` is an example of a text. Like numbers, there is no restriction on the length of texts.

Operations: Examples:
join `"now"^"here" = "nowhere"`
repeat `"-"^^5 = "-----"`
tail `"nowhere"@3 = "where"`
head `"nowhere"|2 = "no"`
number of characters `#"nowhere" = 7`
number of occurrences `"e"#"nowhere" = 2`
selection `"nowhere" item 4 = "h"`
traverse the characters ```FOR c IN "nowhere":     PUT freq[c]+1 IN freq[c]```
smallest character `min "nowhere" = "e"`
largest character `max "nowhere" = "w"`
convert to upper case `upper "NowHere" = "NOWHERE"`
convert to lower case `lower "NowHere" = "nowhere"`
strip spaces `stripped " nowhere " = "nowhere"`

For the operations `@`, `|`, and `item`, the elements of a text are numbered from 1 to the length of the text.

The operations `@` and `|` may be combined to yield any subtext; for example, to obtain the subtext starting at position 3 and having length 4, we may write:

`"nowhere"@3|4 = "wher"`

Such text selections may also be used as addresses. For instance, after

```PUT "nowhere" IN word
PUT "bless" IN word@3|4```

the location `word` contains `"noblesse"` (since `wher` has been replaced by `bless`).

Compounds

A compound is a sequence of values of possibly different types. It is like a record in other languages, but it has no field names. Compounds are useful for multiple `PUT`'s, for parameters, for multi-dimensional tables (`t[i, j]`), but also as values to be put in a table (instead of separate values put in separate tables under the same key). Examples:

```PUT a, b, c IN b, c, a \cyclic permutation
PUT "May", 22 IN anniversary
PUT 1813, anniversary IN date
PUT date IN year, (month, day)
PUT now IN (year, month, day, hour, minute, second)```
Operation: Example: Gives:
Date and time `WRITE now` (1995, 7, 26, 13, 13, 16.976513)

The function `now` returns the date and time now, with the seconds accurate to that supplied by the operating system.

Lists

A list is a sorted sequence of values with multiple occurrences allowed. For example,

`WRITE {"u"; "e"; "a"; "y"; "o"; "i"}`

gives {"a"; "e"; "i"; "o"; "u"; "y"},

`WRITE {3; 2; 1}`

gives {1; 2; 3}, and

`FOR i IN {"ay"; "i"; "eye"; "aye"}: WRITE #i`

gives 2 3 3 1 (which is because ```{"ay"; "i"; "eye"; "aye"}``` gives `{"ay"; "aye"; "eye"; "i"}` ).

The items of a list may be of any type, but all must be of the same type (all texts, or all numbers, etc.) Since there may be multiple occurrences of an entry, you may have lists like `{1; 1; 1}`.

Sorted lists of any type work because an order is associated with each type. For instance:

```2.99 < 3.00
"" < "Z" < "a" < "az" < "b"
("b", "c") < ("z", "a")
{} < {"a"; "z"} < {"b"}```

Instead of `{1; 2; 3; 4; 5; 6; 7}` the range notation `{1..7}` may be used; similarly, `{"a".."c"}` stands for ```{"a"; "b"; "c"}```. Several of these ranges may be combined: the list `{"A".."C"; "a".."c"}` contains six items.

Operations: Examples:
initialise `PUT {"wart"; "eye"; "mouth"} IN face`
add item to list ```INSERT "nose" IN face INSERT "eye" IN face```
remove one instance `REMOVE "wart" FROM face`
number of items `#face = 4`
number of occurrences `"eye"#face = 2`
traverse the items `FOR f IN face: INSERT f IN f2`
smallest (= first) item `min {3; 2} = 2`
largest (= last) item `max {3; 2} = 3`
selection `{1; 9; 8; 9} item 2 = 8`

Because lists are kept sorted there is no need for sorting programs. If a different order is required for the items of a list, it is often useful to create a list of compounds. Suppose texts are wanted in length order:

```PUT {} IN new.face
FOR feature IN face:
INSERT #feature, feature IN new.face```

To output the texts in the desired order, you can then use:

`FOR length, feature IN new.face: WRITE feature /`

(note the use of a multiple name following `FOR`) which would produce:

```eye
eye
nose
mouth```

Tables

Tables are like arrays or tables in other languages, but the keys (= indices) may be of any type, and need not be consecutive:

```PUT {} IN price
PUT 3.50 IN price["jam"]
PUT 2.45 IN price["butter"]
WRITE price```

gives as output on the screen:

`{["bread"]: 1.95; ["butter"]: 2.45; ["jam"]: 3.50}`

Notice that the entries are sorted on the keys. All keys of a table must have the same type, but just as with lists, may be of any type. The items (the stored values) must also all have the same type, but, of course, the types of the keys and the items need not be the same.

Operations: Examples:
initialise `PUT {} IN count`
add entries `FOR f IN face: PUT 0 IN count[f]`
modify entries ```FOR f IN face:     PUT count[f]+1 IN count[f]```
the list of keys `keys count = {"eye"; "mouth"; "nose"}`
length `#count = 3`
number of occurrences in the items `2#count = 1`
number of occurrences in the keys `"nose" # keys count = 1`
traverse the items `FOR i IN count: PUT s+i IN s`
traverse the keys `FOR f IN keys count: WRITE f, count[f] /`
smallest item `min count = 1`
smallest key `min keys count = "eye"`
largest item `max count = 2`
largest key `max keys count = "nose"`
selection of an item `count item 2 = 1`
selection of a key `(keys count) item 2 = "mouth"`
delete entry `DELETE count["nose"]`

The `keys` function plays an important role in nearly all applications of tables.

There is one function on texts, `split`, that splits a text into its space-separated words and returns these as a table:

`split "  now   here  " = {[1]: "now"; [2]: "here"}`

Generic operations

As you may have noticed, several of the operations mentioned work equally for texts, lists and tables. Texts, lists and tables together are called trains. The generic operations are:

Operations: Meaning:
`#` the length
`min` the smallest item
`max` the largest item
`item` selection of an item

The `FOR` command also works generically on trains.

When a generic operation is applied to a table, it is the items of the table that are handled, and not the keys, so `min t`, where `t` is a table, gives the smallest item, and ```min keys t``` gives the smallest key.

For `min` and `max` there are also versions with two operands: `i min t` gives the smallest item of `t` that is larger than `i`. Similarly, ```i max t``` gives the largest item of `t` smaller than `i`. For instance,

```"i" min {"a"; "e"; "i"; "o"; "u"; "y"} = "o"
"i" max {"a"; "e"; "i"; "o"; "u"; "y"} = "e"```

User-defined Commands and Functions

As shown in the `PRINT CELSIUS` example, new commands may be defined with how-to's:

`HOW TO APPEND tail TO text: PUT text^tail IN text`
`HOW TO PREPEND head TO text: PUT head^text IN text`
```HOW TO PRINT text VERTICALLY:
FOR c IN text: WRITE c /```
```HOW TO REVERSE text:
PUT "" IN reverse
FOR c IN text: PREPEND c TO reverse
PUT reverse IN text```

Once these have been given, the commands

```PUT "here" IN word
PREPEND "now" TO word
REVERSE word```

make `word` equal to `"erehwon"`. If we now say

`REVERSE word@4|2`

`word` is made equal to `"erewhon"`.

So a command how-to is to ABC what a procedure or sub-routine is to other languages. The general appearance of user-defined commands is the same as that of predefined commands such as `PUT` ... `IN` ... (though no control commands of the type `WHILE` ... : can be defined by the user).

Similarly, users may define their own functions, such as this one which returns the set of different items occurring in a given list:

```HOW TO RETURN elements collection:
PUT {} IN unique
FOR element IN collection:
IF element not.in unique:
INSERT element IN unique
RETURN unique```

The name of the function (`elements`) and its template operand (`collection`) occur in the first line (values passed to functions are called operands and those passed to commands are called parameters. The how-to should contain one or more `RETURN` commands, specifying the result, which may be of any type, just as the operand may be.

As well as functions with one operand, you may also define functions with two operands, and functions without operands. Here is a function called `with` that has two operands `list1` and `list2`, and a function `origin` that has no operands:

```HOW TO RETURN list1 with list2:
FOR i IN list1: INSERT i IN list2
RETURN list2```
`HOW TO RETURN origin: RETURN (0, 0, 0)`

Functions with more than two operands have to be written as functions with one or two compound operands, e.g.,

`HOW TO RETURN (x, y, z) rotated (pitch, roll, yaw):`

The function `with` above appears to change the value of its operand, but such a change does not affect any location outside the how-to: it changes a copy of the operand which is thrown away upon termination of the invocation of the function.

In contrast to functions, the execution of a command defined by a ```HOW TO``` does change the environment when something is `PUT` `IN` a parameter; in fact, that is the very purpose of commands. When a operand is given to a function, only its value is passed, whereas in the case of a command, the value of the parameter is passed if it has one, and then after the execution of the command, if the value has been changed it is passed back.

The operands for functions and the parameters for commands require no parentheses (except to indicate priorities). For instance, you can write `sin x` and `2*sin x`.

However, you cannot write `sin x * 2` since it is ambiguous, and the system will tell you so. You must write either `(sin x) * 2` or `sin(x*2)`, depending on which you mean. Values of any type may be passed to a how-to, as long as they match up with the operations used in the how-to. For instance, the `elements` function above will work on any train as operand:

`WRITE elements "Mississippi"`

gives as output

`{"M"; "i"; "p"; "s"}`

Names and Locations

If we use a command such as

`PUT {2; 3; 5; 7} IN primes`

as an immediate command (as opposed to inside a how-to), a location is created - unless one already exists - whose name is `primes`. The location stays in existence until the command ```DELETE primes``` is given, and so is referred to as a permanent location. Names of locations used inside a how-to are private to that how-to, and the corresponding locations are temporary: they are alive only as long as the invocation of the how-to lasts.

One way of importing permanent locations into a how-to is by using parameters, but there is also another way. If, in the example of the previous section, there is only a single text for `APPEND`, `REVERSE`, etc., to work on, it is a nuisance to have to pass it as a parameter each time. The how-to's may then be changed to:

```HOW TO APPEND tail:
SHARE text
PUT text^tail IN text```
```HOW TO PRINT VERTICALLY:
SHARE text
FOR c IN text: WRITE c /```

etc.

`SHARE text` indicates that the name `text` in this how-to will not use a location private to the how-to, but will refer to a shared permanent location, either already in existence, or to be created during the invocation of the how-to. Other how-to's wishing to refer to the same `text` should now also ```SHARE text```, since otherwise their use of the name `text` would be private and would introduce a temporary location.

A location should be used consistently for values of one type. Private names may be used for different types of values during the execution of different invocations, but during one invocation the corresponding location may contain only values of the same type. So, if we have defined this `SWAP` command:

`HOW TO SWAP a AND b: PUT a, b IN b, a`

we may use it at one time to swap two numbers, at another time to swap two texts, but never to swap a number and a text.

The system checks this partly statically, i.e. at the time the how-to's are typed in, partly dynamically, i.e. during execution time. Checking is done on a basis of consistency, not on a basis of conformity to declarations, which do not exist in ABC.

Control Commands

There are two conditional commands. In addition to

`IF test:`

(no `ELSE` allowed), ABC also has

```SELECT:
test1:
...
test2:
...
test3:
...```

The first test to succeed determines which alternative is to be executed. At least one test must succeed. Instead of the last test, the keyword `ELSE` may be used, which always succeeds:

```SELECT:
e > 0: INSERT e IN pos
e < 0: INSERT e IN neg
ELSE: PUT nzero+1 IN nzero```

For repetition, apart from `FOR` ... `IN` ..., there is also

```WHILE test:
...```

to repeatedly execute a group of commands while the test is true.

For leaving a command how-to before its end, the command

`QUIT`

is used. It may occur anywhere inside a command how-to.

Random

The function `random` returns an arbitrary approximate number, such that

`0 <= random < 1 .`

The function `choice` returns an arbitrary item from a train. For instance, the command

`PUT choice {"A".."Z"} IN cap`

puts an arbitrary capital letter in `cap`. Likewise,

`PUT choice "Mississippi" IN c`

puts an arbitrary letter from the text `"Mississippi"` in `c`. In the same way, it is possible to make an arbitrary `choice` from the items of a table. The meaning of `choice` may be described in terms of `random` in the following way:

```HOW TO RETURN choice train:
RETURN train item (1+floor(random*#train))```

(This is another example of a how-to which may be used with operands of different types - text, list or table in this case - as long as they are consistent with the operations inside.)

The behaviour of `choice` and `random` is based on a pseudo-random sequence. To make programs replicable, the sequence may be started at a specified point by using a `SET RANDOM` command, e.g. like this:

`SET RANDOM "Today is my birthday."`

or with an invocation with any other expression of any type as a parameter.

Tests

An order is associated with each type, so `<`, `<=`, `=`, `>=`, `>` and `<>` (unequal) are defined for all values having the same type (but not for values of different types). Multiple comparisons are allowed:

`WHILE x < y < z: PUT f y IN y`

To discover if a list or table (or text) contains a certain item (or character), the `in` test may be used:

```SELECT:
i in keys count: PUT count[i]+1 IN count[i]
ELSE: PUT 1 IN count[i]```

Similarly, the test `not.in` tests the absence of an item.

To discover if a number is exact or approximate, the test `exact` is used:

```SELECT:
exact x: WRITE */ x, "over", /* x
ELSE: WRITE "~", x```

Tests may be combined with `AND`, `OR` and `NOT`:

```IF i in keys t AND t[i] > 2: ...
IF NOT (c = "a" OR c = "b"):.```

Such combined tests are performed from left to right. In an `AND` combination, evaluation stops as soon as a failing test is encountered; in an `OR` combination it stops at the first succeeding test.

ABC also has versions of the mathematical quantifiers `SOME`, `EACH` and `NO`:

```IF SOME d IN {2..n-1} HAS n mod d = 0:
WRITE n, "has factor", d```

If the `SOME` test succeeds, the first value found to satisfy the test following `HAS` is put in the location of the name between `SOME` and `IN`. Examples of `NO` and `EACH` are:

```IF NO year, anniversary IN birthday HAS year = 1813:
WRITE "list is incomplete"```
```SELECT:
EACH name IN keys birthday HAS name|1 in "ABC":
WRITE "ABC-composers abound"
ELSE: WRITE name```

Just as a new function may be defined with ```HOW TO RETURN```, a new predicate to be used in tests may be defined with `HOW TO REPORT` :

```HOW TO REPORT a includes b:
REPORT EACH x IN b HAS x in a```

In a predicate how-to, `REPORT` is used instead of `RETURN` to indicate the outcome. To avoid ```REPORT 1 = 1``` or `REPORT 0 = 1`, the commands `SUCCEED` and `FAIL` are available as well. Another version of the `includes` how-to might be:

```HOW TO REPORT a includes b:
FOR x IN b:
IF x not.in a: FAIL
SUCCEED```

As with `HOW TO RETURN`, operands are passed by value and the environment is not affected by changes made by a predicate how-to.

Input/Output

Input from the user at the keyboard is read by a `READ` command, such as

`READ size EG (0, 0)`

where the expression following `EG` specifies the type of the expression to be entered (here a compound of two numbers). The type of the expected expression may be given by, for example, `0` or `""`, or by any other expression. In the following example, the `READ` command demands the input to be of the same type as the items of the list `legal.moves` :

`READ move EG min legal.moves`

`READ` prompts the user, who may then enter any expression of the desired type, using shared names and built-in or user-defined functions.

`READ` with an EG format requires input texts to be quoted, just as in ABC itself. For situations where this is a nuisance, another version of the `READ` command is available:

`READ line RAW`

which interprets the input line as a text and stores it in the location `line`.

For output to the screen, a `WRITE` command is used. As shown above, `WRITE` can handle expressions of any type. Apart from the operations mentioned in Texts, the following operations are useful for formatting purposes:

Operation: Examples:
align left `7*8<<9 = "56 "`
align right `7*8>>9 = " 56"`
centre `7*8><9 = " 56 "`
insert value of expression `"1K is `2**10`" = "1K is 1024"`

These operations work for values of any type, and aren't confined to `WRITE` commands; for instance:

`PUT "1K is `2**10`" IN message`

Refinements

Hierarchical programming in ABC is aided by refinements. These are like light-weight procedures, but:

• refinements belong to a how-to and are written at its end;
• refinements have no parameters or operands;
• refinements have no private names: the meaning of a name used in a refinement is determined by the context at the point where the refinement is used.

Refinements come in three kinds, analogous to the three kinds of how-to's. All three kinds are seen in this how-to to compute the average of a sequence of positive numbers. Note that just as with commands, functions and predicates, the name of a command-refinement is in capital letters, and the names of function- and predicate-refinements are in lower-case:

```HOW TO AVERAGE:
INITIALISE
GET INPUT
WHILE valid:
TREAT
GET INPUT
OUTPUT
INITIALISE: PUT 0, 0 IN sum, n
GET INPUT:
WRITE "Number: "
TREAT: PUT sum+i, n+1 IN sum, n
valid: REPORT i > 0
OUTPUT: WRITE "The average is:", average
average: RETURN sum/n```

Note that function refinements contain a `RETURN` command, and predicate refinements a `REPORT` command. Similarly, command refinements may be left early with the `QUIT` command. For instance, here is a way of writing the elements of a train until an element is greater than 100:

```LOOP:
FOR x IN train:
IF x > 100: QUIT
WRITE x```

Of course, refinements become more useful as programs become longer, and you will see many in the coming chapters.

The ABC Programmer's Handbook by Leo Geurts, Lambert Meertens, and Steven Pemberton