.TL \" Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984.
A User's Guide to the B system
.AU
Steven Pemberton
CWI, Amsterdam
.ds B \fIB\fP
.so bfont.def
.AB
\*B is a new interactive programming language being developed at the CWI.
This report gives a brief introduction to using the current \*B implementation.
It does not teach you about the language, for which you should refer elsewhere.
.AE
.SH
.bp
Introduction
.PP
.de BX
'nh
\v'-\\n(.su/2u'\(br\v'\\n(.su/2u'\|\\$1\|\v'-\\n(.su/2u'\(br\v'\\n(.su/2u'\\h'-\\w'|'u/2u'\l'|0+(\\w'|'u/2u)\(rn'\\h'-\\w'|'u/2u'\l'|0\(ul'\\$2
'hy
..
.de BR
[\\$1]\\$2
..
.de KY
.ie t .BX \\$1 \\$2
.el .BR \\$1 \\$2
..
This guide is a brief introduction to using the current \*B system.
It does not attempt to teach you about the language,
for which you should refer elsewhere.
.PP
Furthermore, certain details such as how to start the system up,
and which keys on your terminal correspond to the keys mentioned,
depend on your local installation, and are not mentioned in this guide.
Keys are just referred to here by their name, such as
.KY accept .
Refer to the ``bterminal(5)'' manual entry for these details.
.PP
Some older \*B systems don't let you make changes to immediate commands,
nor give you suggestions to immediate commands, but only in units.
.SH
Starting up
.PP
The first response you should get from the \*B system when you start it up
is a prompt that looks like this:
.DS
\*(<:>>> _?\*(:>
.DE
The underlined question mark is the indication from the \*B system
that it is expecting input from you.
(In fact, it depends on the sort of terminal 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 in this guide.)
When it follows the three arrows \*(<:>>>\*(:>, called the \fIcommand prompt\fP,
it is expecting you to type in a command.
The question mark is called a \fIhole\fP
and indicates that something should be filled in;
the underline is called the \fIfocus\fP
and shows where you are currently working.
.PP
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:
.DS
\*(<:>>> W_?RITE ?\*(:>
.DE
This extra stuff to the right of the focus is a \fIsuggestion\fP.
Most times that you type a \*(<:W\*(:> as the first letter of a command,
it is because you want a \*(<:WRITE\*(:>.
Therefore the editor 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 the
.KY accept
key to accept the suggestion \(em the editor
then moves to the first unfilled hole in the command,
which in this case is the only one,
and you get:
.DS
\*(<:>>> WRITE _?\*(:>
.DE
You can now type an expression and press the
.KY newline
key.
The system evaluates the expression,
prints the result,
and then gives you a new command prompt.
Here are a few examples of \*(<:WRITE\*(:> commands:
.DS
\*(<:>>> WRITE 2+2
4
>>> WRITE root 2
1.414213562373095
>>> WRITE pi
3.141592653589793\*(:>
.DE
If you make a mistake while typing and spot it before you type
.KY newline ,
an easy way to correct it is to use the
.KY back
key.
Pressing
.KY back
takes you back to the situation before you typed
the last key (\fIexactly\fP the situation,
as you will see clearly after a little use).
If you type
.KY back
twice,
you will be taken back to the situation as it was two keys ago,
and so forth.
You can regard the
.KY back
key as a way of travelling back in time.
.LP
Thus, if you meant to type \*(<:WRITE pi\*(:>,
but instead typed \*(<:WRITE po\*(:>,
you will see this:
.DS
\*(<:>>> WRITE po_?\*(:>
.DE
Now pressing
.KY back
will give you
.DS
\*(<:>>> WRITE p_?\*(:>
.DE
Now you can type the \*(<:i\*(:> and the
.KY newline .
Currently you can only go back a maximum of 100 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.
.PP
If you make a mistake so that the result is illegal \*B,
but don't notice before you press
.KY newline
you will get an error message:
.DS
\*(<:>>> WRITE root 3**2+4**2
*** There's something I don't understand in your command
    WRITE root 3**2+4**2
                 ^
*** The problem is: priorities? use ( and ) to resolve\*(:>
.DE
The problem here is that the system doesn't know
if you want to apply \*(<:root\*(:> to \*(<:3\*(:> or \*(<:3**2\*(:> or \*(<:3**2+4**2\*(:>
and you should use brackets to show which.
.PP
When you type an open bracket,
the system automatically supplies the matching closing bracket for you:
.DS
\*(<:>>> WRITE root(_?)\*(:>
.DE
You now type in the expression
.DS
\*(<:>>> WRITE root(3**2+4**2_?)\*(:>
.DE
You may now type
.KY newline
\^(
.KY accept
will take you over the closing bracket,
but it is not necessary to do this):
.DS
\*(<:>>> WRITE root(3**2+4**2)
5\*(:>
.DE
.LP
You can write any legal \*B value:
.DS
\*(<:>>> WRITE {1..10}
{1; 2; 3; 4; 5; 6; 7; 8; 9; 10}
>>> WRITE 'Hello! '^^3
Hello! Hello! Hello!\*(:>
.DE
Just as with brackets,
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
.KY accept
or type the quote yourself,
in order to position after it.
.PP
Commands typed as a response to the command prompt
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:
.DS
\*(<:>>> P_?UT ? IN ?\*(:>
.DE
Again,
you use
.KY accept
to go to the first hole:
.DS
\*(<:>>> PUT _? IN ?\*(:>
.DE
Here you type an expression,
.DS
\*(<:>>> PUT root 2?_ IN ?\*(:>
.DE
followed by another
.KY accept
to take you to the second hole:
.DS
\*(<:>>> PUT root 2 IN _?\*(:>
.DE
where you can type a target,
followed by
.KY newline :
.DS
\*(<:>>> 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 3\*(:>
.DE
The targets that you create in this way,
through immediate commands,
are called `permanent targets',
because if you stop using the system,
and log out,
and come back later and start using the system again
you will find that the targets are still there,
with the same values as before.
.PP
You can find out which targets exist
by typing two equals signs after the prompt:
.DS
\*(<:>>> ==
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\*(:>
.DE
To get rid of targets you no longer want, use the \*(<:DELETE\*(:> command:
.DS
\*(<:>>> 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\*(:>
.DE
As you can see,
after the \*(<:DELETE\*(:> command both \*(<:a\*(:> and \*(<:b\*(:> have ceased to exist.
.SH
Other Immediate Commands
.PP
In fact,
almost any \*B command can be used as an immediate command;
the only exceptions are the commands used to terminate \*(<:TEST\*(:>s and \*(<:YIELD\*(:>s,
namely \*(<:RETURN\*(:>, \*(<:REPORT\*(:>, \*(<:SUCCEED\*(:> and \*(<:FAIL\*(:>.
.DS
\*(<:>>> 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}
>>> CHOOSE number FROM list
>>> WRITE number
9
>>> CHECK 5 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\*(:>
.DE
Note that a \*(<:CHECK\*(:> command that succeeds doesn't print any message.
Also note carefully that
the target \*(<:i\*(:> used in the \*(<:FOR\*(:> command doesn't exist afterwards.
.PP
When you want to type a \*(<:WHILE\*(:> command,
and you type the initial \*(<:W\*(:>,
the suggestion you get is of course \*(<:W_?RITE ?\*(:>.
Here you must type an \*(<:H\*(:>,
and the system then suggests
.DS
\*(<:>>> WH_?ILE ?:\*(:>
.DE
Now you can press
.KY accept
to go to the hole,
type the test,
and press
.KY newline :
.DS
\*(<:>>> WHILE list <> {}:
        _?\*(:>
.DE
Because the \*B system knows that the commands of a \*(<:WHILE\*(:> must be indented,
it indents for you automatically.
You may now type in the commands to be part of the \*(<:WHILE\*(:>,
and each time the system indents you to the right place.
After the last command you just need to type an extra
.KY newline ,
and the system undoes the indentation one level,
and executes the \*(<:WHILE\*(:>.
(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).
.DS
\*(<:>>> WHILE list <> {}:
        CHOOSE number FROM list
        REMOVE number FROM list
        WRITE number
2 8 4 7 9 5 3 1 5 10
>>> WRITE list
{}\*(:>
.DE
.SH
Finishing a B Session
.PP
The one command that has a different meaning when you type it after a prompt
is \*(<:QUIT\*(:>,
which just terminates the \*B session.
When you type the \*(<:Q\*(:> you will get a suggestion as usual.
.DS
\*(<:>>> Q_?UIT\*(:>
.DE
Here there are no holes,
but you must still press
.KY accept
to accept the suggestion,
before pressing
.KY newline .
.SH
Making your own Commands
.PP
You can create your own commands by typing in a how-to unit
that defines what your command means.
Suppose you type in response to the \*B prompt:
.DS
\*(<:>>> HOW'TO GREET:
        WRITE 'Hello'\*(:>
.DE
The system gives a suggestion for \*(<:HOW'TO\*(:>,
and supplies indentation for you,
just as with \*(<:WHILE\*(:>,
and you finish by pressing
.KY newline
until you get the command prompt again.
Well,
now you've defined your first command,
and can execute it by typing its name after the prompt.
You will notice that after typing the \*(<:G\*(:> you will get a suggestion for it:
.DS
\*(<:>>> G_?REET\*(:>
.DE
Just as with \*(<:QUIT\*(:>,
there are no holes,
but you must
.KY accept
the suggestion.
.DS
\*(<:>>> GREET_?\*(:>
.DE
Now press
.KY newline
and your command gets executed,
and you get the prompt again:
.DS
\*(<:>>> GREET
Hello
>>>\*(:>
.DE
You may use your own commands just like any in-built command:
.DS
\*(<:>>> FOR i IN {1..10}: GREET
HelloHelloHelloHelloHelloHelloHelloHelloHelloHello\*(:>
.DE
.SH
Correcting errors
.PP
Apart from
.KY back ,
another way of correcting errors is to correct a whole line.
Here you use the ability to move the focus about.
Earlier the focus was 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.
.PP
Two of the eight keys for moving the focus are
.KY up
and
.KY down .
.PP
The
.KY up
key moves the focus up to the previous line
so that it includes the whole line.
So if you have the following situation:
.DS
\*(<:>>> FOR i IN {1..3}:
        WRITE /
        GREET
        WRITE /_?\*(:>
.DE
then typing
.KY up
gives you
.DS
\*(<:>>> FOR i IN {1..3}:
        WRITE /
        GREET_____
        WRITE /\*(:>
.DE
Here the hole in the last line has disappeared
(because the line is legal \*B)
and the focus has moved up to the whole of the preceding line.
You may press
.KY up
several time to go up several lines.
So,
pressing
.KY up
again gives:
.DS
\*(<:>>> FOR i IN {1..3}:
        WRITE /_______
        GREET
        WRITE /\*(:>
.DE
The
.KY down
key does the same but in the other direction.
.PP
Now the point of all this is,
that if you have a line in a command or unit that you want to change,
you can move the focus to it,
and press
.KY delete
to get rid of it.
This leaves a hole in its place so that you can type a replacement line:
.DS
\*(<:>>> FOR i IN {1..3}:
        ?_
        GREET
        WRITE /\*(:>
.DE
If you don't want to replace the line,
but completely delete it,
then pressing
.KY delete
again deletes the hole too:
.DS
\*(<:>>> FOR i IN {1..3}:
        GREET_____
        WRITE /\*(:>
.DE
.SH
Changing Existing Units
.PP
Just as you can type two equals signs
to find out what permanent targets you have,
you can type two colons to
find out what units you have in the current workspace.
This gives you a list of the first line of each unit in the workspace:
.DS
\*(<:>>> ::
HOW'TO GREET:\*(:>
.DE
If you want to change any of these units,
you can type a colon followed by the name of the unit you want:
.DS
\*(<:>>> :GREET\*(:>
.DE
(If the unit you want to change is the last unit you typed in
or changed in this session,
or the last unit that you got an error message about,
then you don't even need to type its name:
the system remembers the name of the unit,
so all you need to do is type a single colon.)
.PP
What happens now is that the whole unit is displayed
(or as much as will fit on the screen if it is big)
with the focus on the line you were last at in the unit.
You can now use all the focus moving keys to position
to the lines you want to change,
and change them.
When you have finished,
you use the
.KY exit
key.
.SH
Errors in Units
.PP
If when you type in or change a unit,
the result has an error in it,
you will get an error message from the \*B system.
This may happen when you press
.KY exit ,
or when you run the unit, depending on the sort of error it is.
For instance,
in this unit,
the parameter is \*(<:x\*(:>,
but \*(<:n\*(:> is used instead:
.DS
\*(<:>>> HOW'TO SQUARE x:
        WRITE n*n
>>> SQUARE 4
*** Can't cope with problem in line 2 of your unit SQUARE
    WRITE n*n
*** The problem is: n has not yet received a value\*(:>
.DE
When you get such a message,
it is very easy to make the necessary correction:
since the unit 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:
.DS
\*(<:>>> :
HOW'TO SQUARE x:
    WRITE n*n_________\*(:>
.DE
As you see,
you are positioned at the line that gave the error message.
Now you can either press
.KY delete
and retype the whole line,
or use the other focus-moving keys to focus on only the part that is in error.
.SH
Other Focus Moving Keys
.PP
Apart from
.KY up
and
.KY down
there are six other keys for moving the focus,
two for making the focus smaller:
.KY first
and
.KY last ,
two for enlarging it:
.KY widen
and
.KY extend ,
and two for moving it sideways:
.KY previous
and
.KY next .
.PP
In this case we want to make the focus smaller,
by going to the last part of the line.
Thus,
we can press
.KY last
and we see:
.DS
\*(<:HOW'TO SQUARE x:
    WRITE n*n___\*(:>
.DE
Pressing
.KY delete
deletes the part in the focus,
leaving only a hole:
.DS
\*(<:HOW'TO SQUARE x:
    WRITE ?_\*(:>
.DE
Now we can type the correct expression and then press
.KY exit :
.DS
\*(<:HOW'TO SQUARE x:
    WRITE x*x\*(:>
.DE
Suppose now you have the following unit to solve quadratic equations
(if you don't know what these are,
it doesn't matter):
.DS
\*(<:HOW'TO SOLVE a X2 b X c:
    PUT root (b**2-4*a*c) IN x
    WRITE (-b+x)/2*a, (-b-x)/2*a /

*** There's something I don't understand in line 3 of your unit SOLVE
    WRITE (-b+x)/2*a, (-b-x)/2*a /
                  ^
*** The problem is: priorities? use ( and ) to resolve\*(:>
.DE
The system doesn't know whether to divide by \*(<:2\*(:> or \*(<:2*a\*(:>,
so you must insert brackets.
.DS
\*(<:>>> :
HOW'TO SOLVE a X2 b X c:
    PUT root (b**2-4*a*c) IN x
    WRITE (-b+x)/2*a, (-b-x)/2*a /______________________________\*(:>
.DE
Now we want to narrow down to \*(<:2*a\*(:>.
Pressing
.KY last
gives
.DS
\*(<:HOW'TO SOLVE a X2 b X c:
    PUT root (b**2-4*a*c) IN x
    WRITE (-b+x)/2*a, (-b-x)/2*a /________________________\*(:>
.DE
and then
.KY first
gives
.DS
\*(<:HOW'TO SOLVE a X2 b X c:
    PUT root (b**2-4*a*c) IN x
    WRITE (-b+x)/2*a, (-b-x)/2*a /___________\*(:>
.DE
and another
.KY first
gives
.DS
\*(<:HOW'TO SOLVE a X2 b X c:
    PUT root (b**2-4*a*c) IN x
    WRITE (-b+x)/2*a, (-b-x)/2*a /__________\*(:>
.DE
Now
.KY last
gives us
.DS
\*(<:HOW'TO SOLVE a X2 b X c:
    PUT root (b**2-4*a*c) IN x
    WRITE (-b+x)/2*a_, (-b-x)/2*a /\*(:>
.DE
The key
.KY extend
tries whenever possible to extend the focus to the right.
But it sometimes can't,
if what is to the right isn't associated with what is in the focus.
This is the case here:
the comma is associated with the \fIwhole\fP expression \*(<:(-b+x)/2*a\*(:>,
and so
.KY extend
extends to the left instead:
.DS
\*(<:HOW'TO SOLVE a X2 b X c:
    PUT root (b**2-4*a*c) IN x
    WRITE (-b+x)/2*a__, (-b-x)/2*a /\*(:>
.DE
and once more pressing
.KY extend :
.DS
\*(<:HOW'TO SOLVE a X2 b X c:
    PUT root (b**2-4*a*c) IN x
    WRITE (-b+x)/2*a___, (-b-x)/2*a /\*(:>
.DE
Now we have the expression we want,
and typing an opening bracket encloses the whole expression:
.DS
\*(<:HOW'TO SOLVE a X2 b X c:
    PUT root (b**2-4*a*c) IN x
    WRITE (-b+x)/(?_2*a), (-b-x)/2*a /\*(:>
.DE
Now you can use the focus moves to do the same to the second \*(<:2*a\*(:>.
.LP
The focus move keys are very easy to use.
After a little practice you will find they come very naturally.
.SH
Copying
.PP
It is often the case that you want to duplicate a piece of program.
If the focus is on something other than a hole,
the
.KY copy
key copies whatever is in the focus to what is called the
.I "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,
along with the first bit of what is stored.
.PP
If, however, the focus is on a hole,
then the
.KY copy
key 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.
However,
if the contents of the buffer may not be copied there, you just get a bleep;
for instance you can't copy a \*(<:WRITE\*(:> command to a place where
an expression must be.
.PP
You can use the
.KY copy
key for moving things too:
focus on what you want, press
.KY copy ,
press
.KY 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
.KY copy
again.
.PP
Making a hole is straightforward.
A
.KY newline
always makes a hole on a new blank line
after the line that the focus was positioned on.
An
.KY 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.
Finally, pressing
.KY first
or
.KY last
enough times makes one,
.KY first
in front of the focus,
.KY last
after it.
.PP
You can use the
.KY copy
key for copying between different units too.
Even if you log out, and come back later, and start using \*B again,
the copy buffer is kept.
.PP
Additionally, if the \*(<:[copy buffer]\*(:> message isn't being displayed,
that is, if the copy buffer is empty,
and you
.KY delete
something, whatever you delete is 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
.KY copy
to bring it back, and edit it.
.SH
Renaming and deleting units
.PP
If you change the name of a unit, or the adicity of a \*(<:YIELD\*(:> or \*(<:TEST\*(:>
(such as making a dyadic \*(<:YIELD\*(:> into a monadic one) by changing its heading,
then you get the new unit
.I and
the old one.
So, renaming \*(<:GREET\*(:> into \*(<:HELLO\*(:>, and then giving a \*(<:::\*(:> command
would give:
.DS
\*(<:>>> ::
HOW'TO GREET:
HOW'TO HELLO:
HOW'TO SOLVE a X2 b X c:
HOW'TO SQUARE x:\*(:>
.DE
If you delete the
.I whole
of a unit (by pressing
.KY widen
until the focus is on the whole unit,
and then pressing
.KY delete )
the unit disappears.
Thus deleting \*(<:GREET\*(:> will give you:
.DS
\*(<:>>> ::
HOW'TO HELLO:
HOW'TO SOLVE a X2 b X c:
HOW'TO SQUARE x:\*(:>
.DE
.SH
Changing targets
.PP
You may also use the editor for changing permanent targets.
Just as you use a single colon for editing units,
a single equals followed by the name of a target
will display the contents of the target,
and let you make changes in the usual way.
In fact, you may replace the contents by any
.I expression.
When you press
.KY exit ,
the expression is evaluated, and if all is ok
the value is put in the target.
.SH
Workspaces
.PP
A workspace is a collection of units plus a permanent environment.
You can have several workspaces: to create a new one
you just start \*B up in a new directory in the filestore.
.PP
To move units and targets between workspaces, just use the
.KY copy
key:
start \*B up in the one workspace, save whatever you want to move
in the copy buffer,
exit \*B, move to the destination workspace,
re-enter \*B, and copy the buffer back.
.SH
Record and play
.PP
Sometimes you need to repeat a sequence of keystrokes several times.
For instance, if you want to rename a target in a unit,
you have to do it once for each occurrence of the target.
An easy way to do this is to
.I record
a sequence of keystrokes.
If you press
.KY 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
.KY record
again.
Then pressing
.KY play
plays those recorded keystrokes back.
.PP
So, for instance, focus on the target you want to rename,
press
.KY record ,
press
.KY delete ,
type the new name, and press
.KY record
again.
Then focus on the next occurrence of the target,
and press
.KY play .
.PP
Keystrokes that cause an error during recording are not recorded.
.SH
Redisplaying the screen
.PP
Sometimes the screen can get messed up
(for instance, if your terminal gets accidentally unplugged).
If this happens, or you don't believe what you see on the screen,
you can always get confirmation by pressing
.KY look .
This causes the screen to be redisplayed.
.SH
Interrupting a running command
.PP
If a command is executing, and you want to stop it,
pressing
.KY interrupt
aborts the command
and gives you a prompt again.
.SH
Incomplete units
.PP
If, when typing in or correcting a command or unit,
you press
.KY exit
and there are still unfilled holes,
the system tells you so,
and you must fill or delete them.
If you want to exit leaving the holes, to fill them later,
use the
.KY interrupt
key.
The system won't let you run an incomplete unit.
.SH
Getting help
.PP
Pressing the
.KY help
key gives you a quick summary of all the keys.
Refer to the ``Quick Reference'' card for a brief reminder of the features of
the \*B language,
and the ``Description of \*B'' for more detailed explanations.
.SH
Running \*B in the background
.PP
If your computer system lets you,
you can also run \*B non-interactively.
In this case \*B commands are read from the standard input, and executed.
You may only use normal \*B commands in this case: no focus moves,
or editing, and no \*(<:::\*(:> or \*(<:==\*(:> commands.
