Search                        Top                                  Index
TEACH MATCHARROW                                Aaron Sloman 29 Sep 1996
(Also TEACH MATCHES2)
                                            Updated to use "!" Sept 1996

Using the operator "-->"

This teach file assumes that you have read through TEACH * MATCHES.
It introduces new uses of the POP-11 matcher, not to test a condition,
but to "extract" components of a list unconditionally.


         CONTENTS - (Use <ENTER> g to access required sections)

 -- "">A NEW OPERATION "-->"
 -- " to dig out components of a list">Using "-->" to dig out components of a list
 -- " to extract a "segment" of a list">Using "-->" to extract a "segment" of a list
 -- Using --> to extract items between two given items
 -- You can use "restricted" pattern variables to control the match
 -- Using an integer to restrict the length of a matched segment
 -- Using  --> to extract portions of nested sub-lists
 -- " in a procedure">Using "-->" in a procedure
 -- Some exercises using -->
 -- Further reading

"">-- A NEW OPERATION "-->" ----------------------------------------------

Sometimes you know the general form of a list, but you merely want to
get at one or more specific elements. For instance, you may wish to dig
out the first, or the last element, for some purpose. Often, we want to
perform some operation on all the elements of a list, so we start by
doing it to the first element, and then continue on the remainder. For
this purpose it is sometimes useful to be able to dig out the first
element, and then to dig out all the remaining elements and make a list
of them.

In cases like this where we know in advance that the list will match a
pattern, and we are just using the matcher to dig out components and
assign them to variables, we use the operation '-->', instead of
MATCHES. The only difference is that MATCHES produces a RESULT, which it
leaves on the stack, to be printed out by '=>', or possibly used in a
conditional instruction, which will do one thing if the result is true,
and another thing if the result is false. By contrast '-->' does not
produce a result. It merely does the match. If however it cannot do the
match (i.e. if MATCHES would have produced the result FALSE), then '-->'
causes a mishap to occur. Try the following, to POP11, by using the
LOADLINE command (or the CompileLine menu option from the Compiling
menu):

This example produces a boolean result:

    [1 2 3] matches [1 2 3] =>

as does this

    [1 2 3] matches [3 2 1] =>

Because "matches" produces a true or false result it can be used in
tests, e.g. in conditional instructions or in testing whether to
terminate a loop.

The operator "-->" is different. Try these two:

    [1 2 3] --> [1 2 3] =>

    [1 2 3] --> [3 2 1] =>

Note that the first one does not produce any result, whereas the second
one produces a "MISHAP" and interrupts the program. That means that the
operator "-->" can be used to check that your program is working as it
should do, and if not produce an error message. If everything is OK it
allows the program to continue.

But it also has a more important use.

" to dig out components of a list">-- Using "-->" to dig out components of a list ------------------------

Sometimes you know that a list has exactly five elements, and you
wish to extract the fourth one. You can use the matcher arrow to
check that the list is of the right format (i.e. checking that the
program has not gone wrong before this point) and also assign the
fourth element to a pattern variable. Here is how

    vars item;

    [Fred sat on the mat] --> [= = = ?item =];

    item =>

Compare what happens if you do this:

    [The cat sat on the mat] --> [= = = ?item =];

Look closely at the error message, especially lines starting
with "MISHAP", "INVOLVING"

If a match fails it is undefined what the value of any of the
pattern variables will be. A particular variable may or may not
have been assigned a value before the match failed. Try:

    item =>

Try changinge those examples in various ways to see what happens.


" to extract a "segment" of a list">-- Using "-->" to extract a "segment" of a list -----------------------

You can also use the matcher arrow with the "??" type of pattern
variable to extract portions of a list containing several elements. For
example in these examples it can be used to extract the successive
"tails" of the list:

    vars rest;

    [1 2 3] --> [1 ??rest];

    rest =>

    [1 2 3] --> [1 2 ??rest];

    rest =>

    [1 2 3] --> [1 2 3 ??rest];

    rest =>

You can use "=" if you don't care what the intermediate elements
of the list are, as in

    [the cat sat on the furry mat] --> [= = ??rest];

    rest =>

-- Using --> to extract items between two given items -----------------

What will this do:

    vars list = [every person in the room is a member of the club];

    vars phrase1,phrase2;

    list --> [every ??phrase1 is ??phrase2];

    phrase1 =>

    phrase2 =>

Vary the example and see waht happens.

-- You can use "restricted" pattern variables to control the match ----

A colon ":" following a pattern variable can be used to restrict what
it is matched with. Here are some examples where what follows the colon
is the name of a predicate, a testing procedure, e.g. isword, isnumber,
islist.

Try to work out what the following will do before you use LOADLINE
on them:

    vars
        item, item2,
        testlist = ['a string' 4 cat [a list] 3 dog];


    testlist --> [== ?item:isnumber ==];

    item =>

    testlist --> [== ?item:isstring ==];

    item =>

    testlist --> [== ?item:isword ==];

    item =>

    testlist --> [== ?item:islist ==];

    item =>

You can also use a restriction on one variable to control what is
matched by another, e.g. by using the following pattern to get
the second item following the first number:

    testlist --> [== ?item:isnumber = ?item2 ==];

    item2 =>

What happens if you try to find the item preceding the string? Try this:

    testlist --> [?item2 ?item:isstring == ];

It can't be done with this list.


-- Using an integer to restrict the length of a matched segment -------

You can use an integer following the colon to restricte the length
of a matching list. For example see what happens with these examples:

    vars item, list;

    [1 2 3 4] --> [??list:3 ==];
    list =>

That extracted a list containing the first three items.

Compare

    [1 2 3 4] --> [== ??list:3];
    list =>

You could also search for an element of the "top level" list which
is an embedded list of a given length.

    vars
        list,
        lists = [[a] [a b] [a b c] [a b c d] [a b c d e]];

    lists --> [== ?list:2 ==];
    list =>

    lists --> [== ?list:4 ==];
    list =>

    lists --> [== ?list:8 ==];
    list =>


-- Using  --> to extract portions of nested sub-lists -----------------

Lists can contain other lists. If you know that a list has several
sublists and you wish to extract a list containing the first three
elements of the third sublist it is very easy using a "restricted"
pattern variable, thus:

    vars
        sublist,
        lists = [[ a b ] [ 1 2 3 4] [ A B C D E F] [99 88 66]];

    lists --> [= = [??sublist:3 ==] ==];

    sublist =>


Write down a command to create a list containing the last two elements
of the second  embedded list. It should assign the list [3 4] to the
variable sublist.




" in a procedure">-- Using "-->" in a procedure ---------------------------------

We could use the operation --> to define a procedure to produce the last
element of a given list.

Try compiling this procedure (Load Current Procedure). Note that we
declare result using "vars" to ensure that the pattern element ?result
works as expected.

define final(list) -> result;
    vars result;    ;;; pattern variable

    list --> [== ?result]

enddefine;

Then test it

/*
    final([a b c d]) =>
    final([a]) =>
    final([ [a b] [c d] [e f] ]) =>
    final([]) =>
*/

NOTE: if you don't wish to declare the pattern variable as "vars" you
must precede the whole pattern with "!", as in

define final(list) -> result;
    list --> ![== ?result]
enddefine;

The output local variable "result" is automatically declared as lvars.
So it need not be declared prior to use in the pattern that sets the
value, because the use of "!" allows lvars variables to be used as
pattern variables.

Compile that, and check that the above tests sill all work (apart from
the one that previously produced a mishap).


You could also have used --> to define a procedure to produce the
the 'tail' of a list, i.e. a list containing all but the first element

define tail(list) ->result;
    vars x, result;
    list --> [?x ??result]
enddefine;

Test it

    tail([ a b c d]) =>
    tail ([abcd]) =>

Actually the definition of TAIL is wasteful. It includes the variable X,
whose value is not used. The item '?X' was there just to ensure that
RESULT was not given the whole list. To do this we can use '=', which
matches exactly one item but doesn't care what it is.

define tail(list) ->result;
    vars result;
    list --> [= ??result]
enddefine;

test it:
    tail([a b c d]) =>

Note that, as before, you could leave out the "vars result" if you put
"!" before the opening list bracket.

N.B. in the definition of TAIL it is important to have a space between

    "=" and "??"

for otherwise POP11 will make them 'stick together' to form a bigger
symbol, which it will then not recognize. Try, without the space:

    [1 2 3] --> [ =??result];

Similarly, you could define a procedure head to get the first element.

define head(list) -> result;
    list --> ![?result ==]
enddefine;

    head([ a b c ]) =>
    head([]) =>

actually, Pop-11 already has such a procedure, called hd:

    hd([a b c d])=>

which is also like

    [a b c d](1) =>

(Often, in Pop-11 there is more than one way to do the same thing.
Choose the method which you think makes your programs clearest.)


-- Some exercises using --> -------------------------------------------

Use the match operation --> to define a procedure which produces the
second element of a list. Then test your procedure.

Now define a procedure which will produce a list containing all
but the first and last elements in a list.

define middle(list) -> result;
    vars result;
        list --> .....
enddefine;

complete that and test it with several examples.

Try it using "!" and without the "vars" declaration.



Did you do this?

    define middle(list) -> result;
        list --> ![= ??result = ]
    enddefine;

NB it is important to leave a space between '=' and '??', as explained
previously. Test that:

    middle([mary had a little lamb]) =>

This might be a good point at which to pause, and make notes on
everything you've learnt so far. Try to think of ways in which it
might be useful in a program like Eliza, or some other program which
tries to 'understand' or at least analyse sentences. (What's the
difference?)

Exercise: explain the difference between "matches" and "-->"

    (It may help if you understand how the stack works. See TEACH STACK.)

-- Further reading ----------------------------------------------------

TEACH * RESPOND will help you understand MATCHES better through practice
using it.

For more on the use of "MATCHES" and "-->" to define simple procedures,
See TEACH * MOREMATCH. (This file has not yet been updated for Poplog
version 15 or later.)

For a concise summary  see HELP * MATCHES.

TEACH ARROW gives more practice on the use of ^^ and ^ in lists.

For more on lists, see TEACH LISTS.

TEACH * LISTSUMMARY gives an overview of list manipulating facilities.


--- $poplocal/local/teach/matcharrow
--- Copyright University of Birmingham 1996. All rights reserved. ------