POP-11 provides a special command called `readline()' that gives us what we want. When executed, the `readline()' command prints out a query symbol at the left hand of the window and then waits for something to happen. If the user types something in and hits RETURN, the `readline()' command wakes up and produces as a value, the text the user typed in, in the form of a list. You can test this out by executing the following commands.
vars user_input; readline() -> user_input;An interaction with POP-11, following execution of the two lines above is shown below.
? this is some inputFollowing this, the value printed out by
user_input ==>is
** [this is some input]Note that the value produced by `readline()' is always a list.
The `readline()' command can be used for the purposes of producing greetings. For example
vars name; [Hello. Please type in your name] ==> readline() -> name; [Hello there ^^name, please to meet you] ==>Note the use of the double-hat to `get rid of' the unwanted list-brackets.
Experiment: Write a procedure called `sum' that uses `readline' to read in two numbers from the user. The procedure should then add the two numbers together and print out the result.
[add 3 to 7] [do 56 + 92] [sum 123 and 765]The easiest way to do this in POP-11 is to use the `matches' command (also known as `the matcher'). In the simplest case we use this command in conjunction with the `if' command to find out whether two lists are the identical. For example,
vars input; readline() -> input; if input matches [add 3 to 7] then 3 + 7 ==> endif;will print out the value of 3 + 7 only if you (the user) responded to the `readline()' prompt by typing in `add 3 to 7', because that is the only way that the value of `input' will be identical to [add 3 to 7].
Note the structure of this command. First we have the word `if', then we have the list we are interested in, then the word `matches' followed by the list we want to test against. Following this we have the word `then' followed by any number of valid commands, followed finally by the word `endif'. The commands between the `then' and the `endif' are only done if the first list matches the second.
In fact the two lists do not have to be identical for the match to `succeed'. The second list can be a pattern made up of of literal values and wild-cards. For example,
vars input, x1, x2, x3, answer; readline() -> input; if input matches [?x1 3 ?x2 7] then 3 + 7 -> answer; [the answer is ^answer] ==> endif;will print out [the answer is 11] provided only that you respond to the prompt by typing in four items, the second and fourth of which are `3' and `7'. This happens because `matches' treats any item in the right-hand list that begins with `?' as a wild-card and allows it to be matched with anything in the other list. Thus
if [add 123 and 765 together] matches [?x1 123 ?x2 765 ?x3] then 123 + 765 -> answer; [the answer is ^answer] ==> endif;produces
** [the answer is 888]The names that appear after the queries in the pattern should be variable names, since, as a side effect, the matcher assigns to the wild-card variable the value that the wild-card matches against. Thus, after doing the command above, the values of x1, x2 and x3 are as follows.
x1 ==> ** add x2 ==> ** and x3 ==> ** togetherExperiment: work out the values of `x', `y', `something' and `somethingelse' after we load the following?
vars x, y, something, somethingelse; if [foo 2 bang] matches [?x 2 ?y] then [yes] ==> endif; if [foo 2 bang] matches [?something 2 ?somethingelse] then [no] ==> endif;Experiment: work out which of the following matches prints out [yes] and what are the values given to the variables `x' and `y' in each case?
vars x, y; if [a b c] matches [a ?x c] then [yes] ==> endif; if [the cat sat on the mat] matches [?x sat on the mat] then [yes] ==> endif; if [[the cat] sat on the mat] matches [?y sat on the mat] then [yes] ==> endif; if [] matches [?y] then [yes] ==> endif; vars list; [[a 1] [b 2] [c 3]] -> list; if list matches [[a 1] [b ?x] ?y] then [yes] ==> endif;Experiment: work out what property is shared by every list that matches the pattern [?x ?y ?z]?
POP-11 provides another kind of wild-card which is a variable name preceded by a double query, e.g., `??x'. Double-query wild-cards can match against any sequence of elements in a list. So if we do
if [no cat on the mat] matches [no ??x] then [yes] ==> endif;we get
** [yes]and the value of the variable `x' is the list `[cat on the mat]'. Note the difference between single- and double-query wild-cards. With single-query wild-cards a single item is assigned to the wild-card variable. With double-query wild-cars, a list is assigned to the wild-card variable and this contains the whole sequence of items that were matched.
if [1 2 3 4 5 6 7 8 9] matches [?x 2 ??y] then [yes] ==> endif;prints
** [yes]and values of `x' and `y' are `1' and `[3 4 5 6 7 8 9]', respectively.
But
if [foo 2 3 4 5 6 7 8 9] matches [??x 2 ?y] then [yes] ==> endif;prints nothing since the list does not match the pattern. There is a sequence of items after the 2 in the list and this cannot be matched against a single-query wild-card.
Experiment: find out what value query variables have if matching fails? For example, what is the value of `x' after we do
if [a b] matches [?x c] then [yes] ==> endif;Experiment: Which of the following prints [yes] and why?
vars x, y, z; if [a b c] matches [??x] then [yes] ==> endif; if [] matches [??x] then [yes] ==> endif; if [a b c] matches [a b c ??y] then [yes] ==> endif; if [[a 1] [b 2] [c 3]] matches [??x [?y ?z]] then [yes] ==> endif; if [David] matches [D ??x] then [yes] ==> endif;
vars x, y, z, item; [1 2 3 4 5 6 7 3 8 9] -> list; if list matches [??x ?item ??y ?item ??z] then [the item ^item is duplicated] ==> endif;When executed this code produces
** [the item 3 is duplicated]We do not know in advance where the duplicate items will appear. However, by putting double-query variables (that match anything or nothing) on both sides of both single-query variables, we effectively take account of all possible positions that the duplicated items might appear in the list.
define ask(); vars answer, x, y; [Hello, what are your hobbies?] ==> readline() -> answer; if answer matches [??x music ??y] then [That is nice, I like all kinds of music] ==> else [Oh, I prefer to listen to music] ==> endif; enddefine;If we do `ask();' we get a dialogue such as this:
** [Hello , what are your hobbies ?]
? i like music
** [That is nice , I like all kinds of music]
Using a repeat loop, we can arrange for the `ask' procedure to build up
a list of known hobbies. For example
vars hobbies; [] -> hobbies; define ask(); vars answer, x, y; repeat 999 times [please type in one of your hobbies] ==> readline() -> answer; [^^answer ^^hobbies] -> hobbies; [yes, I like ^^answer too] ==> endrepeat; enddefine;Now the interaction goes on forever, or at least until we press the INTERRUPT key.
ask(); ** [please type in one of your hobbies] ? golf ** [yes , I like golf too] ** [please type in one of your hobbies] ? sailing ** [yes , I like sailing too] ** [please type in one of your hobbies] ? balloons ** [yes , I like balloons too] ** [please type in one of your hobbies] (INTERRUPT key pressed to terminate interaction)Folling this interaction the list of hobbies is
hobbies ==> [balloons sailing golf]Experiment: work out why the list is effectively in reverse order.
vars answer, x, y, z; define ask(); repeat 999 times [Would you like to add a new object to the bugworld?] ==> readline() -> answer; if answer matches [??x yes ??y] then [What do you want to call it?] ==> readline() -> answer; [[name ^^answer]] -> pb_spec; endif; endrepeat; enddefine;To begin a dialigue with this procedure we give the command `ask()'.
ask(); ** [Would you like to add a new object to the bugworld ?] ? yes ** [What do you want to call it ?] ? robert ** [Would you like to add a new object to the bugworld ?] ? no ** [Would you like to add a new object to the bugworld ?] (INTERRUPT key pressed to terminate interaction)As it stands the procedure is not particular helpful. However, we can easily make it more useful by adding in extra commands. For example, we could add in an extra `if' so as to enable the user to decide whether to create a bug or an obstacle. In POPBUGS, an object counts as a bug if it has a bug-like behaviour attribute. The simplest example is the word `pb_forwards'. (Bugs with this behavioural attribute move forwards one step in each cycle of the simulation.) The simplest example of a behaviour value for a non-bug is the word static. Thus we can define the new procedure thus.
define ask(); repeat 999 times [Would you like to add a new object to the bugworld?] ==> readline() -> answer; if answer matches [??x yes ??y] then [What type of object do you want to add?] ==> readline() -> answer; if answer matches [??x bug ??y] then [[behaviour pb_forwards]] -> pb_spec; [added a new bug] ==> endif; if answer matches [??x obstacle ??y] then [[behaviour static]] -> pb_spec; [added a new obstacle] ==> endif; endif; endrepeat; enddefine;Now the interaction becomes (slightly) more interesting.
ask(); ** [Would you like to add a new object to the bugworld ?] ? yes ** [What type of object do you want to add ?] ? a nice big bug ** [added a new bug] ** [Would you like to add a new object to the bugworld ?] ? yes ** [What type of object do you want to add ?] ? just an obstacle please ** [added a new obstacle] ** [Would you like to add a new object to the bugworld ?] (INTERRUPT key pressed to terminate interaction)
vars hobbies; [] -> hobbies; define ask(); vars answer, x, y; repeat 999 times [please type in one of your hobbies] ==> readline() -> answer; if answer matches [bye] then return; endif; [^^answer ^^hobbies] -> hobbies; [yes, I like ^^answer too] ==> endrepeat; enddefine;With this procedure, the user can exit from the interaction by typing `bye'.
[mary votes for the tories] [george votes the same way his father votes] [it takes a long time to count up the votes]
[the man that was here last night left his coat] [that was the best thing you ever did] [if I did not know better I would say that was good news]but not
[the best thing you ever did was good news]
** [Please type in your numbers] ? 50 80 25 15 ** [the total is: 170]
[one two three four five six seven] matches
readline() command for obtaining input from the user if ... matches ... executes commands if one list matches the other ? matches wild-card that matches a single item ?? matches wild-card that matches a sequence return causes a procedure to stop executing