@(#)p5 8.1 (Berkeley) 06/08/93
The Script Interpreter.
The learn .R program itself merely interprets scripts. It provides facilities for the script writer to capture student responses and their effects, and simplifies the job of passing control to and recovering control from the student. This section describes the operation and usage of the driver program, and indicates what is required to produce a new script. Readers only interested in the existing scripts may skip this section.
The file structure used by learn is shown in Figure 2. There is one parent directory (named \f2lib\f1\^) containing the script data. Within this directory are subdirectories, one for each subject in which a course is available, one for logging (named log ), and one in which user sub-directories are created (named play ). The subject directory contains master copies of all lessons, plus any supporting material for that subject. In a given subdirectory, each lesson is a single text file. Lessons are usually named systematically; the file that contains lesson n is called Ln .
.KF
Figure 2: Directory structure for learn |
lib |
play |
student1 |
files for student1... |
student2 |
files for student2... |
files |
L0.1a lessons for files course |
L0.1b |
... |
editor |
... |
(other courses) |
log |
When learn .R is executed, it makes a private directory for the user to work in, within the learn .R portion of the file system. A fresh copy of all the files used in each lesson (mostly data for the student to operate upon) is made each time a student starts a lesson, so the script writer may assume that everything is reinitialized each time a lesson is entered. The student directory is deleted after each session; any permanent records must be kept elsewhere.
The script writer must provide certain basic items in each lesson:
Learn .R tries to minimize the work of bookkeeping and installation, so that most of the effort involved in script production is in planning lessons, writing tutorial paragraphs, and coding tests of student performance.
The basic sequence of events is as follows. First, learn creates the working directory. Then, for each lesson, learn reads the script for the lesson and processes it a line at a time. The lines in the script are: (1) commands to the script interpreter to print something, to create a files, to test something, etc.; (2) text to be printed or put in a file; (3) other lines, which are sent to the shell to be executed. One line in each lesson turns control over to the user; the user can run any X commands. The user mode terminates when the user types yes , no , ready , or answer . At this point, the user's work is tested; if the lesson is passed, a new lesson is selected, and if not the old one is repeated.
Let us illustrate this with the script for the second lesson of Figure 1; this is shown in Figure 3. .KF
Figure 3: Sample Lesson |
Of course, you can print any file with "cat". |
In particular, it is common to first use |
"ls" to find the name of a file and then "cat" |
to print it. Note the difference between |
"ls", which tells you the name of the files, |
and "cat", which tells you the contents. |
One file in the current directory is named for |
a President. Print the file, then type "ready". |
#create roosevelt |
this file is named roosevelt |
and contains three lines of |
text. |
#copyout |
#user |
#uncopyout |
tail -3 .ocopy >X1 |
#cmp X1 roosevelt |
#log |
#next |
3.2b 2 |
Lines which begin with # are commands to the learn script interpreter. For example,
.ul #print
causes printing of any text that follows, up to the next line that begins with a sharp.
.ul #print file
prints the contents of file ; it is the same as .ul cat file but has less overhead. Both forms of #print have the added property that if a lesson is failed, the .ul #print will not be executed the second time through; this avoids annoying the student by repeating the preamble to a lesson.
.ul #create filename
creates a file of the specified name, and copies any subsequent text up to a # to the file. This is used for creating and initializing working files and reference data for the lessons.
.ul #user
gives control to the student; each line he or she types is passed to the shell for execution. The #user mode is terminated when the student types one of yes , no , ready or answer . At that time, the driver resumes interpretation of the script.
.ul #copyin
.ul #uncopyin
Anything the student types between these commands is copied onto a file called .ul .copy. This lets the script writer interrogate the student's responses upon regaining control.
.ul #copyout
.ul #uncopyout
Between these commands, any material typed at the student by any program is copied to the file .ul .ocopy. This lets the script writer interrogate the effect of what the student typed, which true believers in the performance theory of learning usually prefer to the student's actual input.
.ul #pipe
.ul #unpipe
Normally the student input and the script commands are fed to the X command interpreter (the ``shell'') one line at a time. This won't do if, for example, a sequence of editor commands is provided, since the input to the editor must be handed to the editor, not to the shell. Accordingly, the material between .ul #pipe and .ul #unpipe commands is fed continuously through a pipe so that such sequences work. If .ul copyout is also desired the .ul copyout brackets must include the .ul pipe brackets.
There are several commands for setting status after the student has attempted the lesson.
.ul #cmp file1 file2
is an in-line implementation of cmp , which compares two files for identity.
.ul #match stuff
The last line of the student's input is compared to stuff , and the success or fail status is set according to it. Extraneous things like the word answer are stripped before the comparison is made. There may be several #match lines; this provides a convenient mechanism for handling multiple ``right'' answers. Any text up to a # on subsequent lines after a successful #match is printed; this is illustrated in Figure 4, another sample lesson.
.KF
Figure 4: Another Sample Lesson |
What command will move the current line |
to the end of the file? Type |
"answer COMMAND", where COMMAND is the command. |
#copyin |
#user |
#uncopyin |
#match m$ |
#match .m$ |
"m$" is easier. |
#log |
#next |
63.1d 10 |
.ul #bad stuff
This is similar to #match , except that it corresponds to specific failure answers; this can be used to produce hints for particular wrong answers that have been anticipated by the script writer.
.ul #succeed
.ul #fail
print a message upon success or failure (as determined by some previous mechanism).
When the student types one of the ``commands'' yes , no , ready , or answer , the driver terminates the #user command, and evaluation of the student's work can begin. This can be done either by the built-in commands above, such as #match and #cmp , or by status returned by normal X commands, typically grep and test . The last command should return status true (0) if the task was done successfully and false (non-zero) otherwise; this status return tells the driver whether or not the student has successfully passed the lesson.
Performance can be logged:
.ul #log file
writes the date, lesson, user name and speed rating, and a success/failure indication on .ul file. The command
.ul #log
by itself writes the logging information in the logging directory within the learn hierarchy, and is the normal form.
.ul #next
is followed by a few lines, each with a successor lesson name and an optional speed rating on it. A typical set might read
25.1a 10 25.2a 5 25.3a 2
indicating that unit 25.1a is a suitable follow-on lesson for students with a speed rating of 10 units, 25.2a for student with speed near 5, and 25.3a for speed near 2. Speed ratings are maintained for each session with a student; the rating is increased by one each time the student gets a lesson right and decreased by four each time the student gets a lesson wrong. Thus the driver tries to maintain a level such that the users get 80% right answers. The maximum rating is limited to 10 and the minimum to 0. The initial rating is zero unless the student specifies a different rating when starting a session.
If the student passes a lesson, a new lesson is selected and the process repeats. If the student fails, a false status is returned and the program reverts to the previous lesson and tries another alternative. If it can not find another alternative, it skips forward a lesson. bye , bye, which causes a graceful exit from the .ul learn system. Hanging up is the usual novice's way out.
The lessons may form an arbitrary directed graph, although the present program imposes a limitation on cycles in that it will not present a lesson twice in the same session. If the student is unable to answer one of the exercises correctly, the driver searches for a previous lesson with a set of alternatives as successors (following the #next line). From the previous lesson with alternatives one route was taken earlier; the program simply tries a different one.
It is perfectly possible to write sophisticated scripts that evaluate the student's speed of response, or try to estimate the elegance of the answer, or provide detailed analysis of wrong answers. Lesson writing is so tedious already, however, that most of these abilities are likely to go unused.
The driver program depends heavily on features of X that are not available on many other operating systems. These include the ease of manipulating files and directories, file redirection, the ability to use the command interpreter as just another program (even in a pipeline), command status testing and branching, the ability to catch signals like interrupts, and of course the pipeline mechanism itself. Although some parts of .ul learn might be transferable to other systems, some generality will probably be lost.
A bit of history: The first version of learn had fewer built-in words in the driver program, and made more use of the facilities of X . For example, file comparison was done by creating a cmp process, rather than comparing the two files within learn . Lessons were not stored as text files, but as archives. There was no concept of the in-line document; even #print had to be followed by a file name. Thus the initialization for each lesson was to extract the archive into the working directory (typically 4-8 files), then #print the lesson text.
The combination of such things made learn slower. The new version is about 4 or 5 times faster. Furthermore, it appears even faster to the user because in a typical lesson, the printing of the message comes first, and file setup with #create can be overlapped with the printng, so that when the program finishes printing, it is really ready for the user to type at it.
It is also a great advantage to the script maintainer that lessons are now just ordinary text files. They can be edited without any difficulty, and X text manipulation tools can be applied to them. The result has been that there is much less resistance to going in and fixing substandard lessons.