TEACH READLINE                                Aaron Sloman Feb 23 1979
                                                     Improved Feb 1984

=== USING READLINE ===================================================

READLINE is a procedure used for writing conversational programs.  It
takes no inputs, and produces as output a list containing words typed at
the terminal by the user.

Try the following:

    readline() =>

This will produce the prompt '?', to which you can type something and
press RETURN:

    ? this is my input to readline

READLINE will read in what you typed and make a list of it. The print
arrow '=>' will then print it out:

    ** [this is my input to readline]

Try again:

    readline() =>
    ? happy birthday to you
    ** [happy birthday to you]

Don't type the '?' : thats the prompt produced by READLINE.

-- SAVING THE LIST IN A VARIABLE --------------------------------------

READLINE is a procedure of no arguments, which asks the system to hand
it the next line of text which you type in. It then breaks that line up
into separate items (e.g. words and numbers) and makes a list of those
items, which it returns as its  result. The result was printed out by
the print-arrow, above. Instead, you can assign the result to a
variable. Try:

    vars input;
    readline() -> input;
    ? 1 or 2 words and numbers
    input =>

-- CHANGING THE PROMPT ------------------------------------------------

The only warning that READLINE is waiting for you to type something in
Is the '?' prompt. You can write a procedure which prints out a message
to tell you that input is wanted, and then uses READLINE to read in the
input. Try this:

    define getline(message) -> result;
        message =>
        readline() -> result;
    enddefine;


That defined a procedure which produces as its result whatever READLINE
reads in. You can test it, thus:

    getline( [ please type your name ] ) -> input;
    ** [please type your name]
    ? joe bloggs

The line with two asterisks will be printed out before the prompt '? '.
Nothing more will be printed out when you press RETURN. But you can
print out what was assigned to INPUT, thus:

    input =>
    ** [joe bloggs]

Try that, and variations of your own:

    getline( [ whats the day today ] ) -> input;
    ** [whats the day today]
    ? tuesday 13 march
    input =>
    ** [tuesday 13 march]

Notice that the computer prints something out before you type the second
line in each group. NB don't put an apostrophe in 'WHAT'S'. See TEACH
APOSTROPHE.

Similarly, you can't include an apostrophe in the response to READLINE.
E.g. if you type

    ? it's tuesday

you'll get a mishap as POP11 misinterprets the APOSTROPHE as a string quote.

-- A SIMPLE NUMBER QUIZ -----------------------------------------------

You can use GETLINE to write a simple quizzing program.

    define quiz(x,y);
        vars input, sum;
        x + y -> sum;
        getline([ whats ^x plus ^y ]) -> input;
        if  input = [^sum]
        then    [well done] =>
        else    [wrong you dummy - try again] =>
            quiz(x,y);
        endif;
    enddefine;


Actually, typing 'you dummy' in a REAL teaching program would probably
be a very bad strategy, but never mind.

Put that in a file, with your procedure GETLINE, defined above

Now test your procedure. Try:

    quiz(3,4);
    quiz(-5, 99);

try giving it some wrong answers.

You can  perhaps see more clearly what is happening if you
trace all the procedures:
    trace readline getline quiz;
    quiz(3,4);

etc. Try that.

-- USING RANDOM TO SELECT THE NUMBERS ---------------------------------

You can make the computer choose the numbers for QUIZ, by using the
procedure RANDOM. It takes a positive integer as input, and produces an
unpredictable integer less than that as output. Try this:

    repeat 5 times random(20) => endrepeat;

Which may print something like:
    ** 10
    ** 12
    ** 10
    ** 2
    ** 8

You may get different results printed out. You can use a bigger 'upper
bound' for the random numbers:

    repeat 5 times random(100) => endrepeat;
    ** 28
    ** 93
    ** 93
    ** 9
    ** 12

Now you can test your own arithmethic thus:

    untrace readline getline quiz;
    repeat 10 times
        quiz(random(100), random(100))
    endrepeat;

This could produce an interaction like:
    ** [whats 52 plus 90]
    ? 145
    ** [wrong you dummy - try again]
    ** [whats 52 plus 90]
    ? 142
    ** [well done]
    ** [whats 4 plus 77]
    ? 81
    ** [well done]
    ** [whats 17 plus 15]

etc....

-- DEFINING A PROCEDURE TO CALL QUIZ ----------------------------------
You can define a procedure which will call QUIZ over and over again
until you interrupt, by typing CTRL-C, as follows:

    define play();
        repeat
          quiz(random(50), random(50))
        endrepeat
    enddefine;

Try that, then type

    trace quiz readline;
    play();
    ** [whats 32 plus 46]
    ? 78
    ** [well done]
    ** [whats 42 plus 43]
    ? 95
    ** [wrong you dummy - try again]
    ** [whats 42 plus 43]
    ?
If you then press CTRL-C you will interrupt this. If you are testing
this inside the editor, you may have to press the screen refresh button
afterwards to clear the mess off the screen.

-- STOPPING BY MEANS OF A CONTROL VARIABLE ----------------------------

You can define a procedure which will call QUIZ over and over again
until you type in BYE, as follows.

First redefine the procedure QUIZ so that if the INPUT is the word "bye"
then it assigns TRUE a variable FINISHED, then exits.
Replace line 5 of procedure QUIZ with an additional test as follows:

    define quiz(x,y);
        vars input, sum;
        x + y -> sum;
        getline([ whats ^x plus ^y ]) -> input;
        if input = [bye] then
            true -> finished
        elseif  input = [^sum]
        then    [well done] =>
        else    [wrong you dummy - try again] =>
            quiz(x,y);
        endif;
    enddefine;

You can test the effect thus
    vars finished;
    false -> finished;
    repeat
      quiz(random(100),random(100));
    quitif(finished);
    endrepeat;

    ** [whats 36 plus 23]
    ? 59
    ** [well done]
    ** [whats 46 plus 22]
    ? bye

It stops without the need for CTRL-C.

Now you can define a procedure PLAY which sets up FINISHED and repeatedly
calls QUIZ
    define play();
        vars finished;
        false -> finished;
        repeat;
          quiz(random(50), random(50));
        quitif(finished)
        endrepeat;
        [bye -- hope you enjoyed the quiz]=>
    enddefine;

Notice that the line
    quitif(finished)

could have been expressed
    quitfi(finished = true)

which might have been easier to understand, but comes to the same thing
for POP-11.

Try all that, then type
    trace quiz readline;
    play();

-- A MORE MODULAR VERSION OF QUIZ AND PLAY ----------------------------

This is not a very good strategy, since the procedure QUIZ is used to
directly change a variable (FINISHED) which really belongs to another
procedure. This sort of thing can produce errors and make programs hard to
debug. It would be better to alter QUIZ so that it produces a result, which
is TRUE or FALSE, depending on whether quizzing should stop. That result
could be assigned to a variable in PLAY, which uses the value of that
variable to decide what to do. PLAY can use a different name for that
variable. I.e. in writing the procedure PLAY you would then not need to
know what variables were used in  QUIZ. Thus the task of programming
could be shared between two people.

The procedure heading for QUIZ could be something like:

    define quiz(x,y) -> finished;

Make sure that FALSE is assigned to FINISHED inside QUIZ if the input is a
number. E.g.
    if input = [bye] then true -> finished
    ...

The line after repeat in PLAY could then go:

        quiz(random(50), random(50)) -> finished;

followed by
        quitif(finished)

as before, or
        quiz(random(50), random(50)) -> done;
        quitif(done)

In the latter case VARS FINISHED would have to be replaced by
VARS DONE;


To learn how to define a procedure so as to produce results, using an
'output local' variable, see TEACH DEFINE.

-- MAKING THE BOUNDS VARIABLE -----------------------------------------

So far we have assumed that numbers between 1 and 50 are acceptable for
the quiz. But you might want to be able to have easier quizzes. So you
can define the procedure PLAY so that it takes in two numbers which it
gives to RANDOM to get the inputs for QUIZ. So if PLAY is re-defined to
have to input variables, say NUM1 and NUM2. Then instead of just 50,
NUM1 and NUM2 can be used in the line which calls quiz.

    define play(num1,num2);

        .....

            quiz(random(num1), random(num2) -> finished

        ....
    enddefine;

Then test your program by trying an easy quiz:

    play(10,10);

-- GENERALISING THE QUIZ ----------------------------------------------

The technique demonstrated here can be used for defining programs which
play games, or repeatedly read in a sentence and respond to it, etc. As
an exercise try altering QUIZ so that it tests multiplication, using "*"
instead of "+".


Then alter PLAY so that it asks whether you want to do multiplications
or additions. Alter QUIZ so that PLAY can call QUIZ with an input which
is "*" or "+", and depending which it is it will do either a
multiplication or an addition.

There is in fact a version of GETLINE in the POP11 library, so you don't
actually need to define your own. You can just use it. Besides GETLINE
and READLINE POP11 includes several procedures for reading things,
e.g. ITEMREAD, READITEM, NUMBERREAD, LISTREAD. It is best to avoid them
unless you are an expert and know exactly what you are doing. READLINE
and GETLINE should suffice for almost all purposes.

TEACH * RESPOND may prove a useful exercise to try next, if you have not
already done it.

See also HELP * READLINE, *GETLINE, *REQUESTLINE
