The ABC Programmer's Handbook by Leo Geurts, Lambert Meertens, and Steven Pemberton
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.
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.
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 >>> ?
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.
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.
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 >>> ?
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 >>> ?
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.
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.
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.
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.
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.
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
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.
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.
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.
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
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.
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.
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
>>> ?
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"
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
>>> ?
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:
------------############------------
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.
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: >>> ?
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.
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
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
*** 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
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.
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
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 >>> ?
Operation | Effect |
---|---|
|
display help summary |
|
visit a how-to |
|
visit last how-to |
|
list how-to's |
|
visit a permanent location |
|
visit last permanent location |
|
list permanent locations |
|
visit a workspace |
|
visit last workspace |
|
list workspaces |
|
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). |
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
Copyright © 1990, 2002, Leo Geurts, Lambert Meertens, and Steven Pemberton. All rights reserved.