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

CHAPTER 3

Using ABC

INTRODUCTION

This chapter is an introduction to using the ABC system: how to type in ABC programs, change them, and run them.

Throughout the chapter, the notation accept is used to represent the operation accept. This isn't an actual key on the keyboard, but represents whatever key is used for the accept operation, since different computers have different keyboards, and since anyway you can decide for yourself which key is used for which operation. Pressing help gives you a quick summary of all operations and the keys you use for them. Typing '?' will always give you this summary as well, except if you are typing where a question mark is allowed (in a text or comment).

How you can change which key means what is described in the appendix on the implementations.

TYPING TO ABC

The first response you get from the ABC system when you start it up is a prompt that looks like this:

>>> ?

The underlined question mark is the indication from the ABC system that it is expecting input from you. (In fact, it depends on the sort of screen you have whether it is underlined, displayed in reverse video, or what. In any case it is displayed in some special way, and we shall use underlining here.) When it follows the three arrows >>>, called the command prompt , it is expecting you to type in a command. The question mark is called a hole and indicates that something should be filled in; the underline is called the focus and shows where you are currently working.

2.1 Suggestions

You can fill this hole by typing in a WRITE command for instance: you type a W (which you don't have to type in upper-case: the system knows that it may only be upper-case here), and you immediately see:

>>> W?RITE ?

This extra stuff to the right of the focus is a suggestion . Most times that you type a W as the first letter of a command, it is because you want a WRITE. Therefore the system suggests this, with an additional hole for the expression that you want to write. If you do want a WRITE (as in this case) you may press accept to accept the suggestion - the focus then moves to the first unfilled hole in the command, which in this case is the only one, and you get:

>>> WRITE ?

You can now type an expression and press newline. The system evaluates the expression, displays the result, and then gives you a new command prompt. Here are a few examples of WRITE commands and their output:

>>> WRITE 2+2
4
>>> WRITE root 2
1.414213562373095
>>> WRITE pi
3.141592653589793
>>> WRITE 2**100-1
1267650600228229401496703205375
>>> ?

2.2 Undoing mistakes

If you make a mistake while typing and spot it before you type newline, an easy way to correct it is to use undo. Pressing undo takes you back to the situation before you typed the last key (exactly that situation, as you will see clearly after a little use). If you type undo twice, you will be taken back to the situation as it was two keys ago, and so forth. Think of undo as a way of travelling back in time.

So if you meant to type WRITE pi but instead typed WRITE po, you get:

>>> WRITE po?

Now pressing undo will give you

>>> WRITE p?

Now you can type the i and the newline. Repeatedly using undo instead will give you the following sequence:

>>> WRITE p?
>>> WRITE ?
>>> W?RITE ?
>>> ?

Because of memory constraints, you can only go back a limited number of keystrokes, and in any case only as far as the command prompt (and thus not back to previous commands). You will see other ways to correct mistakes shortly.

If you should use undo once (or more times) too often, you can use redo to undo the effects of undo. Almost any operation can be undone with undo (exceptions are exit, interrupt, and newline when it results in an exit), so don't be afraid to experiment - if something goes wrong you can always undo it.

2.3 Typing brackets and quotes

If you make a mistake so that the result is illegal ABC, but don't notice before you press newline you will get an error message:

>>> WRITE root 9+16
*** There's something I don't understand
    WRITE root 9+16
                ^
*** The problem is: ambiguous; use ( and ) to resolve
>>> ?

The problem here is that the system doesn't know if you want to apply root to 9 or 9+16 and you should use parentheses to show which.

When you type an open bracket, the system automatically supplies the matching closing bracket for you:

>>> WRITE root(?)

You now type in the expression

>>> WRITE root(9+16?)

You may now type newline (accept will take you over the closing bracket, but it is not necessary to do this):

>>> WRITE root(9+16)
5
>>> ?

You can write any legal ABC value:

>>>  WRITE {1..10}
{1; 2; 3; 4; 5; 6; 7; 8; 9; 10}
>>> WRITE "Hello! "^^3
Hello! Hello! Hello!
>>> ?

Just as with parentheses, the system automatically supplies the closing brace }, and the closing quote ". In the latter case, where you want to type something after the closing quote you may either use accept or type the quote itself, in order to position after it.

IMMEDIATE COMMANDS

Commands typed as a response to the command prompt (like all those seen up to now) are called ' immediate' commands, since they are executed immediately. Another example is the PUT command. Just as with WRITE, when you type the first letter of the command, the system provides a suggestion:

>>> P?UT ? IN ?

Again, you use accept to go to the first hole:

>>> PUT ? IN ?

Here you type an expression,

>>> PUT root 2? IN ?

followed by another accept to take you to the second hole:

>>> PUT root 2 IN ?

where you can type a name, followed by newline:

>>> PUT root 2 IN a
>>> PUT root 3 IN b
>>> WRITE a
1.414213562373095
>>> WRITE b
1.732050807568877
>>> WRITE a, b
1.414213562373095 1.732050807568877
>>> WRITE a*a, b*b
2.000000000000000 3.000000000000000
>>> ?

3.1 Permanent locations

The locations that you create in this way, through immediate commands, are called permanent locations because if you stop using the system and come back later and start using the system again you will find that they are still there, with the same values as before.

You can find out which permanent locations exist by typing two equals signs after the prompt:

>>>  ==
a b
>>> PUT "hello", {1..10} IN message, list
>>> ==
a b list message
>>> WRITE list
{1; 2; 3; 4; 5; 6; 7; 8; 9; 10}
>>> WRITE message
hello
>>> ?

3.2 Deleting locations

To get rid of locations you no longer want, use the DELETE command:

>>> DELETE a, b
>>> ==
list message
>>> WRITE a
*** Can't cope with problem in your command
    WRITE a
*** The problem is: a has not yet received a value
>>> ?

As you can see, after the DELETE command both a and b have ceased to exist.

3.3 Finishing an ABC session

The one command that has a different meaning when you use it as an immediate command is QUIT, which just terminates the ABC session. When you type the Q you will get a suggestion as usual.

>>> Q?UIT

Here there are no holes, but you must still accept the suggestion, before pressing newline.

3.4 Other immediate commands

In fact, almost any ABC command can be used as an immediate command; the exceptions are the commands that are only used in how-to's: SHARE, RETURN, REPORT, SUCCEED and FAIL.

>>> WRITE list
{1; 2; 3; 4; 5; 6; 7; 8; 9; 10}
>>> INSERT 5 IN list
>>> REMOVE 6 FROM list
>>> WRITE list
{1; 2; 3; 4; 5; 5; 7; 8; 9; 10}
>>> PUT choice list IN number
>>> WRITE number
9
>>> CHECK 9 in list
>>> CHECK 6 in list
*** Your check failed in your command
    CHECK 6 in list
>>> FOR i IN list: WRITE 10*i
10 20 30 40 50 50 70 80 90 100
>>> ==
list message number
>>> ?

Note that a CHECK command that succeeds doesn't display any message, and that the location i used in the FOR command doesn't exist afterwards.

3.5 Interrupting a running command

If a command is executing, and you want to stop it, pressing interrupt aborts the command, giving the message

*** interrupted

followed by the command prompt. Don't worry if you don't get the prompt immediately; especially with some very long calculations, the system has to clean up some intermediate values before it is ready to accept new input.

MORE ON TYPING

When you want to type a WHILE command, and you type the initial W, the suggestion you get is of course

>>> W?RITE ?

The system always matches the suggestion to what you have typed, so if you type an H here the system then suggests

>>> WH?ILE ?:

Now you can press accept to go to the hole, type the test, and press newline:

>>> WHILE list <> {}:
        ?

Similarly, to type a READ RAW command, after typing an R, you get

>>> R?ETURN ?

You then type an E and get

>>> RE?AD ? EG ?

You can now accept this suggestion, and type the address:

>>> READ line? EG ?

Now type a ( capital) R, and the line becomes:

>>> READ line R?AW

(typing a space followed by a lower-case r has the same effect). Now you can type an accept or newline.

Because ABC matches its suggestions to what you have typed, you can always type the whole command out, letter for letter. Typing WRITE space will give you the same result as typing W accept.

4.1 Indentation

Because the ABC system knows that the commands of a WHILE must be indented, it indents for you automatically. So, having typed the first line of a WHILE

>>> WHILE list <> {}:
        ?

you may type in the commands that you want to be part of the WHILE, and each time the system indents you to the right place:

>>> WHILE list <> {}:
        PUT choice list IN number
        REMOVE number FROM list
        WRITE number
        ?

After the last command you just need to type an extra newline, and the system undoes the indentation one level, and executes the WHILE:

>>> WHILE list <> {}:
        PUT choice list IN number
        REMOVE number FROM list
        WRITE number
2 8 4 7 9 5 3 1 5 10
>>> WRITE list
{}
>>> ?

If there is only one simple command to be repeated, it may be on the same line as the WHILE, but doesn't have to be:

>>> WHILE number in list: REMOVE number FROM list

4.2 Capital letters

As you will have remarked, you hardly ever have to type a capital letter: the ABC system usually knows where a letter must be a capital, and so supplies it for you, even if you don't use the shift key.

However, there are a small number of places where both lower- and upper-case letters are allowed and where you do therefore have to use the shift key, for instance in tests for SOME, EACH, NO, NOT, AND, and OR, and for ELSE. But in any case, you only have to use the shift key for the first letter: ABC then knows that the rest of the word must be in upper case.

If you type a command out full, not using accept, you also have to use the shift key sometimes. For instance, to type PUT a IN b letter for letter, you have to type the I as a capital, since a lower-case i is also allowable after the a.

4.3 Redisplaying the screen

Sometimes the screen can get messed up (for instance, if it gets accidentally unplugged). If this happens, or you don't believe what you see on the screen, you can always get confirmation by pressing look. This causes the screen to be redisplayed.

THE FOCUS

Apart from undo, another way of correcting errors is to correct a whole line. Here you use the ability to move the focus about. Up to now, the focus has been a single character, just the hole. However, the focus may be more than one character: it may be several characters, a whole command, or even several commands.

5.1 Moving the focus up and down lines

One way of moving the focus is using upline and downline. The operation upline moves the focus up to the previous line so that it includes the whole line. Similarly, downline moves to the next line. So if you have the following situation:

>>> WHILE list <> {}:
        PUT choice list IN number
        REMOVE number FROM list
        WRITE number?

then typing upline gives you

>>> WHILE list <> {}:
        PUT choice list IN number
        REMOVE number FROM list
        WRITE number

Here the hole in the last line has disappeared (because the line is legal ABC) and the focus has moved up to the whole of the preceding line. You may press upline several times to go up several lines. So, pressing upline again gives:

>>> WHILE list <> {}:
        PUT choice list IN number
        REMOVE number FROM list
        WRITE number

5.2 Correcting whole lines

If you have a line that you want to change, you can move the focus to it and press delete to get rid of it. This leaves a hole in its place so that you can type a replacement line:

>>> WHILE list <> {}:
        ?
        REMOVE number FROM list
        WRITE number

If you don't want to replace the line, but completely delete it, then pressing delete again deletes the hole too:

>>> WHILE list <> {}:
        REMOVE number FROM list
        WRITE number

Remember that undo works with any operation, so if you accidentally delete the wrong piece of text, undo will bring it back again.

MAKING YOUR OWN COMMANDS

You can create your own commands by typing in a how-to that defines what you want your command to do. In response to the ABC prompt, type an h:

>>> H?OW TO ?:

type accept:

>>> HOW TO ?:

and type GREET followed by newline. This creates a new how-to called GREET (if you are using a machine with a slow disk like a floppy you'll notice some disk activity here as the system writes some information to disk), and the line you just typed is redisplayed against the left edge of the screen (this is to give you the longest possible line length). Notice that the system supplies the indentation for you, just as with WHILE:

HOW TO GREET:
    ?

You can now type commands to define what GREET should do. For instance, type WRITE "Hello" in the normal way, followed by exit or by repeatedly typing newline until you get the command prompt again. (An exit, by the way, can't be undone.)

HOW TO GREET:
    WRITE "Hello"
>>> ?

You give your own commands just as with built-in commands by typing its name after the prompt. You will notice that after typing the G you will get a suggestion for it:

>>> G?REET

Just as with QUIT, there are no holes, but you must accept the suggestion.

>>> GREET?

Now press newline and your command gets executed, and you get the prompt again:

>>> GREET
Hello
>>> ?

You may use your own commands just like any built-in command:

>>> FOR i IN {1..10}: GREET
HelloHelloHelloHelloHelloHelloHelloHelloHelloHello
>>> ?

If the command you define has parameters, you get holes in the suggestion, just as with normal commands. For instance, suppose you prefer LET a BE 10 to ABC's PUT 10 IN a. Well, then you can define the following how-to:

HOW TO LET a BE b:
    PUT b IN a

Now typing an L, you get the following:

>>> L?ET ? BE ?

You can then use accept in the usual way.

6.1 Functions

You make a function in the same way. You type h:

>>> H?OW TO ?:

accept:

>>> HOW TO ?:

then r:

>>> HOW TO R?ETURN ?:

and accept again:

>>> 
HOW TO RETURN ?:

and then, for instance, reversed t, followed by newline:

HOW TO RETURN reversed t:
    ?

Now type the following commands, followed by exit:

HOW TO RETURN reversed t:
    IF t = "": RETURN ""
    RETURN (reversed(t@2)) ^ t|1
>>> ?

Now you can use this function like the built-in functions of ABC:

>>> WRITE reversed "deliver"
reviled
>>> WRITE reversed "emit"
time
>>> WRITE reversed reversed "emit"
emit
>>> ?

6.2 Predicates

Predicates (how-to's that test a condition) are created in just the same way. Type h:

>>> H?OW TO ?:

accept:

>>> HOW TO ?:

r:

>>> HOW TO R?ETURN ?:

e:

>>> HOW TO RE?PORT ?:

and accept:

>>> HOW TO REPORT ?:

Now you can type, for instance, palindromic t and newline:

HOW TO REPORT palindromic t:
    ?

and then the body of the how-to:

HOW TO REPORT palindromic t:
    REPORT t = reversed t
>>> CHECK palindromic "madam"
>>> CHECK palindromic "rats live on no evil star"
>>> CHECK palindromic ""
>>> CHECK palindromic "I"
>>> CHECK palindromic "madman"
*** Your check failed in your command
    CHECK palindromic "madman"

6.3 Refinements

Refinements come after the commands of the body of a how-to. For example, suppose you have typed this:

HOW TO ORACLE:
    INPUT
    WHILE more:
        OUTPUT
        INPUT
        ?

pressing newline reduces the indentation one level:

HOW TO ORACLE:
    INPUT
    WHILE more:
        OUTPUT
        INPUT
    ?

and pressing newline again gives a suggestion for a refinement:

HOW TO ORACLE:
    INPUT
    WHILE more:
        OUTPUT
        INPUT
?: ?

Type the name (if it is to be in upper-case, you must type at least the first letter of the name in upper-case), followed by accept or newline:

HOW TO ORACLE:
     INPUT
     WHILE more:
         OUTPUT
         INPUT
INPUT: ?

You can now type in the command or commands of the refinement. More refinements can follow the first in the same way:

HOW TO ORACLE:
     INPUT
    WHILE more:
        OUTPUT
        INPUT
INPUT: READ qn RAW
?: ?
HOW TO ORACLE:
    INPUT
    WHILE more:
        OUTPUT
        INPUT
INPUT: READ qn RAW
more: REPORT qn <> ""
OUTPUT: WRITE ans[which]
which: RETURN ("n" # qn) mod 2
ans: RETURN {[0]: "Yes"; [1]: "No"}
?: ?

Now you can type newline to exit.

>>> ORACLE
Are you happy?
Yes
Are you unhappy?
No
>>> ?

6.4 Making changes

Just as you can type two equals signs to find out what permanent locations you have, you can type two colons to find out what how-to's you have. This gives you a list of the first line of each how-to:

>>>  ::
HOW TO GREET:
HOW TO LET a BE b:
HOW TO ORACLE:
HOW TO RETURN reversed t:
HOW TO REPORT palindromic t:
>>> ?

If you want to visit one, to change it or just to look at its definition, you can type a colon followed by its name, for instance:

>>> :GREET

(you have to type the first letter in upper-case for command how-to's), or:

>>> :reversed

If the how-to you want to visit is the last one you typed in or changed, or the last how-to that you got an error message about, then you don't even need to type its name: the system remembers its name, so all you need to do is type a single colon. The system also gives you suggestions for the names of command how-to's.

What happens now is that the whole how-to (or as much as will fit on the screen if it is big) is displayed with the focus on the line you were last at. You can now move the focus to the lines you want to change, and change them. When you have finished, you use exit.

If a how-to gets so large that it doesn't all fit on the screen, then the ABC system displays as much of it as possible and displays a bar on the bottom line of the screen to indicate which part of it is visible. For instance, this would show you that you are looking at roughly the middle third of the how-to:

------------############------------

6.5 Correcting errors

If you type in or change a how-to and the result has an error in it, you will get an error message from the ABC system. This may happen when you press exit, or when you run the how-to, depending on what sort of error it is. For instance in this function, the operand is called x, but n is used instead:

>>> HOW TO RETURN square x:
        RETURN n*n
>>> WRITE square 4
*** Can't cope with problem in line 2 of square
    RETURN n*n
*** The problem is: n has not yet received a value
>>> ?

When you get such a message, it is very easy to make the necessary correction: since the how-to you want to change is the last one that you got an error message for, you only need to type a colon after the prompt:

>>>  :
HOW TO RETURN square x:
    RETURN n*n

As you see, you are positioned at the line that gave the error message. Now you can either press delete and retype the whole line, or move the focus to the part that is in error, and deal only with that. How you do that is described shortly.

When typing in or correcting a command or how-to, if you press exit and there are still unfilled holes, the system tells you so, and you must fill or delete them.

6.6 Renaming and deleting how-to's

You can change the name of a how-to, and the number of parameters, by changing its heading (for instance by deleting the first line, and retyping it). So, renaming GREET into HELLO, and then giving a :: command would give:

>>>  ::
HOW TO HELLO:
HOW TO LET a BE b:
HOW TO ORACLE:
HOW TO RETURN reversed t:
HOW TO RETURN square x:
HOW TO REPORT palindromic t:
>>> ?

If you delete the whole of a how-to (by putting the focus on the last line and repeatedly pressing delete to delete each line, or by widening the focus until it is on the whole how-to, and then pressing delete ) the how-to disappears. (Widening is explained shortly.)

Thus deleting HELLO like this will give you:

>>> ::
HOW TO LET a BE b:
HOW TO ORACLE:
HOW TO RETURN reversed t:
HOW TO RETURN square x:
HOW TO REPORT palindromic t:
>>> ?

OTHER FOCUS MOVES

Apart from upline and downline there are four other groups of focus operations: first and last to make the focus smaller, widen and extend to enlarge it, previous and next  to move it sideways, and up, down, left and right for moving a single hole focus about.

Remember that undo works with any operation, so if you accidentally use the wrong focus move, undo will move it back again.

7.1 Making the focus smaller

In the case of the faulty function square above, we want to make the focus smaller by going to the last part of the line.

HOW TO RETURN square x:
    RETURN n*n

The operation last works by narrowing the focus to the last part of what is enclosed. Thus, pressing last we see:

HOW TO RETURN square x:
    RETURN n*n

Pressing delete deletes the part in the focus, leaving only a hole:

HOW TO RETURN square x:
    RETURN ?

Now we can type the correct expression and then press exit:

HOW TO RETURN square x:
    RETURN x*x
>>> ?

To give you more of an idea of what last does, here is a sequence of them:

 FOR i IN {1..10}: WRITE i*i
 FOR i IN {1..10}: WRITE i*i
 FOR i IN {1..10}: WRITE i*i
 FOR i IN {1..10}: WRITE i*i
 FOR i IN {1..10}: WRITE i*i?

The operation first narrows the focus to the first enclosed part of the focus. Consider the following function:

>>> HOW TO RETURN all.chars:
    WRITE {" ".."~"}
>>> WRITE all.chars
*** There's something I can't resolve in all.chars
    WRITE {" ".."~"}
*** The problem is: function returns no value
>>> ?

The problem is WRITE has been used, when it should have been RETURN, since this is a function how-to, and not a command. So, we type a colon after the prompt:

>>> :
HOW TO RETURN all.chars:
    WRITE {" ".."~"}

Pressing first narrows the focus to just the keyword:

HOW TO RETURN all.chars:
    WRITE {" ".."~"}

Pressing delete deletes the focus:

HOW TO RETURN all.chars:
    ? {" ".."~"}

and now we can type RETURN followed by exit:

HOW TO RETURN all.chars:
    RETURN {" ".."~"}
>>> ?

To give you more of an idea what first does, here is what happens with a sequence of them:

FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
?FOR i IN {1..10}: WRITE i*i

7.2 Making the focus larger

The operation widen enlarges the focus to the next larger object. For example, if you have this:

>>> PUT {"bread"; "butter" } IN shopping

or this:

>>> PUT {"bread" ; "butter"} IN shopping

widen gives you

>>> PUT {"bread"; "butter" } IN shopping

and a delete removes both entries:

>>> PUT {?} IN shopping

Here is a sequence of widen:

FOR i IN {?1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i

The operation extend extends the focus to the right if possible, and otherwise to the left. For instance, in the following situation

>>> PUT {"bread" ; "butter"} IN shopping

extend gives you

>>> PUT {"bread"; "butter"} IN shopping

and pressing delete deletes the first item:

>>> PUT {?"butter"} IN shopping

Similarly, if you have this:

>>> PUT {"bread"; "butter" } IN shopping

extend gives you

>>> PUT {"bread"; "butter" } IN shopping

and delete then deletes the second item:

>>> PUT {"bread"?} IN shopping

Here is a sequence of extends:

FOR i IN {?1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i
FOR i IN {1..10}: WRITE i*i

As you can see, extend usually enlarges the focus at a slower rate than widen.

7.3 Moving the focus sideways

The operation next moves the focus to the next object to the right. For instance, to focus on the expression of a PUT command:

PUT a*a IN b

press first:

PUT a*a IN b

and then next:

PUT a*a IN b

Here are some examples of first and next in action:

WHILE list <> {}:
    PUT choice list IN number
    WRITE number
    REMOVE number FROM list

first:

WHILE list <> {}:
    PUT choice list IN number
    WRITE number
    REMOVE number FROM list

next:

WHILE list <> {}:
    PUT choice list IN number
    WRITE number
    REMOVE number FROM list

first:

WHILE list <> {}:
    PUT choice list IN number
    WRITE number
    REMOVE number FROM list

next:

WHILE list <> {}:
    PUT choice list IN number
    WRITE number
    REMOVE number FROM list

first:

WHILE list <> {}:
    PUT choice list IN number
    WRITE number
    REMOVE number FROM list

next:

WHILE list <> {}:
    PUT choice list IN number
    WRITE number
    REMOVE number FROM list

first:

WHILE list <> {}:
    PUT choice list IN number
    WRITE number
    REMOVE number FROM list

next:

WHILE list <> {}:
    PUT choice list IN number
    WRITE number
    REMOVE number FROM list

first:

WHILE list <> {}:
    PUT choice list IN number
    WRITE n?umber
    REMOVE number FROM list

next:

WHILE list <> {}:
    PUT choice list IN number
    WRITE nu?mber
    REMOVE number FROM list

The operations last and previous work exactly the same as first and next but in the opposite direction.

7.4 Moving a single hole

The operations up, down, left and right make a hole before the focus, position on it, and then move it one line up or down, or one character left or right. For example, here is a sequence of left:

WHILE list <> {}:
WHILE ?list <> {}:
WHILE? list <> {}:
WHIL?E list <> {}:
WHI?LE list <> {}:
WH?ILE list <> {}:
W?HILE list <> {}:
?WHILE list <> {}:

Here is a sequence of down:

WHILE list <> {}:
    PUT choice list IN number
    REMOVE number FROM list
    WRITE number
WHILE list <> {}:
    PUT? choice list IN number
    REMOVE number FROM list
    WRITE number
WHILE list <> {}:
    PUT choice list IN number
    REM?OVE number FROM list
    WRITE number
WHILE list <> {}:
    PUT choice list IN number
    REMOVE number FROM list
    WRI?TE number

The operations right and up work exactly the same, but in the other directions.

7.5 Using a mouse

Finally, if your system has a mouse, you can use it to position the focus. Clicking at any position positions the focus on the largest complete thing that begins at that point. So for instance, with

WHILE list <> {}:
    PUT choice list IN number
    REMOVE number FROM list
    WRITE number

clicking on the W of WHILE will focus on the whole WHILE command; clicking on the l of the first occurrence of list will focus on list <> {}; clicking on the { will focus on {}; clicking on the i of list will focus just on that letter; and so on.

COPYING AND RECORDING

Quite often you will want to duplicate a piece of program. If the focus is on something other than a hole, copy copies whatever is in the focus to what is called the copy buffer and lets you know that there is something in the copy buffer by displaying the words [Copy buffer] at the bottom of the screen.

If, however, the focus is on a hole, copy copies the contents of the buffer into that hole. The [Copy buffer] message then disappears, though actually the contents of the buffer remain, so you can continue to use it.

Of course, you can only copy something back into a hole where it would fit - for instance, you can't copy a command to where an expression is expected. In that case you would just get a beep.

You can use copy for moving things too: focus on what you want, press copy, press delete twice to delete it and the hole that gets left after the first delete, move to where you want, make a hole, and press copy again.

For example, suppose you have the following how-to:

HOW TO AVERAGE tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    WRITE sum/#tl
>>> AVERAGE {1..3}
2
>>> AVERAGE {1}
1
>>> AVERAGE {}
*** Can't cope with problem in your command AVERAGE
    WRITE sum/#tl
*** The problem is: in i/j, j is zero
>>> ?

The WRITE should only be done if tl is not empty, so it must be put in an IF command. So we visit the how-to:

>>> :
HOW TO AVERAGE tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    WRITE sum/#tl

Press copy:

HOW TO AVERAGE tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    WRITE sum/#tl
[Copy buffer]

Press delete:

HOW TO AVERAGE tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    ?
[Copy buffer]

Type IF #tl > 0 and accept:

HOW TO AVERAGE tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    IF #tl > 0: ?
[Copy buffer]

and then copy again:

HOW TO AVERAGE tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    IF #tl > 0: WRITE sum/#tl?

Making a hole to copy to is straightforward: for instance, a newline always makes a hole on a new blank line after the line that the focus was positioned on; accept always takes you to the first hole on a line, or if there is no hole on the line, then it makes one at the end of the line; and left or right makes a hole to the left or right of the first character of the focus.

You can also use copy for copying between different how-to's: you visit the one how-to, do the copy, exit, visit the second how-to, and copy the text back.

If the [Copy buffer] message isn't being displayed, that is, if the copy buffer is empty or has at least been copied once, and you delete something, whatever you delete is silently put into the copy buffer; similarly if the copy buffer is empty, each immediate command is stored in the copy buffer. Thus if you mis-type an immediate command, you can use copy to bring it back, and change it.

You never need to empty the copy buffer. Even if it's got something in it that you don't actually need, another copy will always replace it with the new text.

The copy buffer is kept between sessions: if you end the ABC session, and come back later, and start using ABC again, its contents are still there.

Remember that undo works with any operation, so if you accidentally copy the wrong piece of text, undo will uncopy it.

8.1 Dealing with brackets and quotes

The ABC system always ensures that you have matching brackets and quotes. This means that you can never insert or delete just one of a pair, but must handle both at once. Inserting is easy: you just focus on what you want to have in brackets:

PUT root x + 1 IN a

and type an open bracket:

PUT (?root x)+ 1 IN a

Deleting, you have to copy the contents, delete the whole, and copy the contents back:

PUT 1+(root x ) IN a

copy and widen

PUT 1+(root x) IN a

delete

PUT 1+? IN a

copy

PUT 1+root x? IN a

8.2 Recording

Sometimes you need to repeat a sequence of keystrokes several times. For instance, if you want to rename a location in a how-to, you have to do it once for each occurrence of the name. An easy way to do this is to record a sequence of keystrokes. If you press record the message [Recording] appears at the bottom of the screen, and any keys that you type thereafter are processed normally and recorded at the same time, until you press record again. Then pressing play plays those recorded keystrokes back.

So, for instance, focus on the name you want to change, press record, press delete, type the new name, and press record again. Then focus on the next occurrence of the name, and press play.

Keystrokes that cause an error during recording are not recorded.

WORKSPACES

A workspace is a collection of how-to's and permanent locations. You can have several workspaces. When you first use ABC you are in a workspace called 'first'. To visit another workspace, called programs say, you type '>programs' after the prompt:

>>>  >programs
>>> ?

If the workspace doesn't yet exist, the system creates a new empty workspace with that name before visiting it.

To find out which workspaces you have, you type two >'s:

>>> >>
first >programs
>>> ?

As you can see, the current workspace is marked.

Any how-to's and locations that you create are kept in the workspace where you are working, and these are different than how-to's and locations with the same name in other workspaces:

>>> PUT "greetings" IN message
>>> ==
message
>>> ?

Typing a single > after the prompt takes you back to the previous workspace you were in (first in this case), and the name of the workspace is displayed as a reminder:

>>> >
>first
>>> ==
list message number
>>> WRITE message
hello
>>> ?

When you leave a workspace, if it is empty (i.e. it contains no how-to's and locations) it is deleted:

>>> >>
>first programs
>>> >programs
>>> ==
message
>>> WRITE message
greetings
>>> DELETE message
>>> ==
>>> >first
>>> >>
>first
>>> ?

You can always recreate it of course by visiting it in the normal way:

>>> >programs
>>> ==
>>> >>
first >programs
>>> ?

The current workspace and the last visited how-to in each workspace are remembered between sessions. When you restart ABC, you are put in the workspace you were last in, and its name is displayed.

9.1 Changing the contents of locations

You may also change the contents of permanent locations in the same manner as changing how-to's. Just as you use a single ':' for visiting how-to's, a single ' =' followed by the name of a location will display the contents of the location, and let you make changes. In fact, you may replace the contents by any expression When you press exit, the expression is evaluated, and if all is ok the value is put in the location.

9.2 Moving things between workspaces

To move how-to's and values between workspaces, just use copy: starting in the one workspace, save whatever you want to move in the copy buffer, visit the destination workspace, and copy the buffer back. If you are copying a whole how-to, create and visit a dummy how-to in the destination workspace (for instance HOW TO X:), delete its contents, and then copy the buffer back.

SOME COMMON MISTAKES

Most error messages from ABC are self-explanatory. For instance

*** Can't cope with problem in your command
    PUT i+1 IN i
*** The problem is: i has not yet received a value

However, there are a couple of cases that need a little elaboration.

10.1 Uninitialised locations

*** There's something I can't resolve in your command
    INSERT 0 IN list
*** The problem is: list hasn't been initialised

Just as you can't add 1 to i until i has been given a value, you can't insert an item in a list until that list has got a value. Even if the initial value should be the empty list, you must explicitly start with it:

PUT {} IN list

Similarly with tables:

*** There's something I can't resolve in your command
    PUT 0 IN table[i]
*** The problem is: table hasn't been initialised

You can't add an element to a table until that table has been initialised. Again, if you want to start with an empty table, write

PUT {} IN table

10.2 Incompatible types

The message 'Cannot reconcile the types in your how-to' means that you are trying to use a value in an incompatible way. For instance inserting a text in a list of numbers:

*** Cannot reconcile the types in your command
    INSERT "John" IN nlist
*** The problem is: I thought nlist was of type EG {0}

The type is displayed as an example type, as you might use in a READ EG. So "" represents a text, 0 represents a number, {0} represents a list of numbers, and so on.

Incompatible types can occur in a number of ways, for instance, if you use INSERT where you meant PUT, or vice-versa, or if you use the wrong type of value as the key to a table.

The ABC system is reasonably clever at deducing type errors; if somewhere in a how-to you have

PUT keys t IN list

then it deduces that t is some kind of table, so that if later in the same how-to you have

WRITE root t

it will complain:

*** I thought t was of type EG {[?]: ?}

in other words, it can see that it was a table, but doesn't know the type of the keys or items. On the other hand, if in the same how-to, you have

WRITE 1 + min list

then it can deduce that the keys of t must be numbers, and so will say in the error message for root t:

*** I thought t was of type EG {[0]: ?}

and so on.

In any case, you should look at what types the locations have in the command at fault, and the other uses of the locations in question, and it will usually be clear what the problem is. Note that you can't use one location for values of different types: in this case you should use different locations.

10.3 Ambiguous expressions

If you are used to other programming languages, it is initially very easy to forget the outer pair of parentheses in

PUT (sin(x+y))**2 IN z

If you leave them out, you get this message:

*** ambiguous expression; please use ( and ) to resolve

Often you can save a pair of parentheses by reversing the operands:

WRITE (max keys t)+1
WRITE 1 + max keys t

AN EXAMPLE

Suppose we want to change the AVERAGE command given earlier so that it uses a separate function that returns the sum of the elements of a list or table. So we start off with

HOW TO AVERAGE tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    IF #tl>0: WRITE sum/#tl

and want to finish with

HOW TO AVERAGE tl:
    IF #tl>0: WRITE (sum tl)/#tl
HOW TO RETURN sum tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    RETURN sum

First we have to alter AVERAGE so that it uses the new function:

>>> :AVERAGE
HOW TO AVERAGE tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    IF #tl>0: WRITE sum/#tl

Press upline twice:

HOW TO AVERAGE tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    IF #tl>0: WRITE sum/#tl

press extend

HOW TO AVERAGE tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    IF #tl>0: WRITE sum/#tl

press copy (so that we can re-use the two commands for the body of sum) and then delete:

HOW TO AVERAGE tl:
    ?
    IF #tl>0: WRITE sum/#tl
[Copy buffer]

Press delete again:

HOW TO AVERAGE tl:
    IF #tl>0: WRITE sum/#tl
[Copy buffer]

Now we have to alter the WRITE to use the new function: press last

HOW TO AVERAGE tl:
    IF #tl>0: WRITE sum/#tl
[Copy buffer]

last

HOW TO AVERAGE tl:
    IF #tl>0: WRITE sum/#tl
[Copy buffer]

first

HOW TO AVERAGE tl:
    IF #tl>0: WRITE sum/#tl
[Copy buffer]

Type an open bracket:

HOW TO AVERAGE tl:
    IF #tl>0: WRITE (?sum)/#tl
[Copy buffer]

Type right three times (or accept and left ):

HOW TO AVERAGE tl:
    IF #tl>0: WRITE (sum?)/#tl
[Copy buffer]

and type a space and tl:

HOW TO AVERAGE tl:
    IF #tl>0: WRITE (sum tl?)/#tl
[Copy buffer]

Now exit. Now we want to use the copied text to make the new function. Type h:

>>> H?OW TO ?:
[Copy buffer]

accept:

>>> HOW TO ?:
[Copy buffer]

Type r:

>>> HOW TO R?ETURN ?:
[Copy buffer]

and accept again:

>>> HOW TO RETURN ?:
[Copy buffer]

Type sum tl followed by newline:

HOW TO RETURN sum tl:
    ?
[Copy buffer]

press copy:

HOW TO RETURN sum tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum?

and then newline:

HOW TO RETURN sum tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    ?

Type r:

HOW TO RETURN sum tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    R?ETURN ?

accept:

HOW TO RETURN sum tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    RETURN ?

Type sum and then exit.

HOW TO RETURN sum tl:
    PUT 0 IN sum
    FOR x IN tl: PUT sum+x IN sum
    RETURN sum
>>> ?

SUMMARY OF OPERATIONS

Operation Effect

?

display help summary

:name

visit a how-to

:

visit last how-to

::

list how-to's

=name

visit a permanent location

=

visit last permanent location

==

list permanent locations

>name

visit a workspace

>

visit last workspace

>>

list workspaces

QUIT

end session

up down left right

Make the focus a hole, and go one line up or down, or one character left or right.

upline downline

Move the focus to the whole line above or below.

previous next

Move the focus to the preceding or following object.

widen

Enlarge the focus to the next enclosing object.

extend

Enlarge the focus to the right, or if this is not possible, to the left.

first last

Reduce the focus to the first or last enclosed object.

delete

Delete the focus. If the copy buffer is empty, silently save the contents of the focus there.

copy

If the focus is more than a hole, copy its contents to the copy buffer. If the focus is a hole, copy the contents of the copy buffer into the hole.

accept

Move the focus to the first hole on the first line that the focus is in, or to after the first enclosing closing parenthesis, brace or quote, whichever comes first, or otherwise to the end of the line.

newline

Go to a new line, or if on an empty line, decrease the indentation one level, or otherwise do an exit.

undo

Undo the effect of the last key stroke, whatever it was (except interrupt and exit or a newline that causes a visit or an exit, and undo itself).

redo

Undo the effect of the last undo.

record

Start recording all keystrokes typed. If already started, stop recording.

play

Play recorded keystrokes back.

look

Redisplay screen.

help

Display which keys are used for which operation.

exit

Exit current how-to, or command (can't be undone).

interrupt

Interrupt running command (can't be undone).

Running ABC non-interactively

On some systems, you can also run ABC non-interactively. In this case ABC commands and data are read from the standard input. You may only use normal ABC commands in this case: no focus moves, or changing operations, and no ::, ==, and >> commands.

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