

Sep 13 00:15 1984  chapter.0 Page 1


preface:-- PREFACE
preface:-- Why POP-11?
preface:-- A brief history
preface:-- The editor
preface:-- Interactive programming
preface:-- Declarative and procedural languages
preface:-- The need for procedures
preface:-- Monitors
preface:-- TEACH files and the VED editor
preface:-- The  HELP command
preface:-- The REF command
preface:-- Acknowledgements
chapter.1:-- Introduction
chapter.1:-- The ROOMS Exercise
chapter.1:-- Exercise on the ROOMS example
chapter.1:-- Searching for information
chapter.1:-- Finding several rooms
chapter.1:-- Exercises
chapter.2:-- The POP-11 language
chapter.2:-- Some POP-11 data-types
chapter.2:-- Some POP-11 actions
chapter.2:-- Built in and user-defined procedures
chapter.2:-- Errors and error messages
chapter.2:-- Syntactic and semantic errors
chapter.2:-- Comments in POP-11 programs
chapter.2:-- Expressions: some examples
chapter.2:-- Imperatives: some examples
chapter.2:-- Using infix operators
chapter.2:-- Procedures which produce results
chapter.2:-- Two forms of print-arrow
chapter.2:-- Other printing procedures
chapter.2:-- Conditionals and conditions
chapter.2:-- Predicates
chapter.2:-- Summary of syntactic roles
chapter.2:-- Word-formation rules in POP-11
chapter.2:-- Revision questions
chapter.2:-- Built in POP-11 data types
chapter.3:-- THE STACK
chapter.3:-- Assignment and the stack
chapter.3:-- Non-destructive assignment "->>"
chapter.3:-- Procedures and the stack
chapter.3:-- Assignment as a two stage operation
chapter.3:-- The stack and arithmetic expressions
chapter.3:-- Exercise
chapter.3:-- Multiple assignments
chapter.3:-- Some procedures which work on the stack
chapter.3:-- Clearing items from the stack (erase)
chapter.3:-- Procedures communicate via the stack
chapter.3:-- The DOT-notation for procedure calls
chapter.3:-- Removing unwanted items from the stack
chapter.3:-- Swapping items using the stack
chapter.3:-- Conditionals and the stack
chapter.4:-- Arithmetic: basic facilities
chapter.4:-- Other arithmetic procedures
chapter.4:-- Using a radix other than 10
chapter.4:-- POP_PR_RADIX, POP_PR_PLACES and POP_PR_EXPONENT







Sep 13 00:15 1984  chapter.0 Page 2


chapter.4:-- Illustrating popradians
chapter.4:-- RANDOM
chapter.4:-- Random decimal numbers
chapter.4:-- Exercises
chapter.4:-- Precedence and parentheses
chapter.4:-- Defining new infix procedures
chapter.4:-- Testing for equality and inequality
chapter.4:-- Numerical comparisons
chapter.5:-- Defining procedures
chapter.5:-- Executing (calling, running, applying) a procedure
chapter.5:-- Procedures with more than one output local
chapter.5:-- Different types of procedures
chapter.5:-- Loops: instructions to do something repeatedly
chapter.5:-- UNTIL <condition> DO <action> ENDUNTIL
chapter.5:-- REPEAT <number> TIMES <action> ENDREPEAT
chapter.5:-- WHILE <condition> DO <action>  ENDWHILE
chapter.5:-- 'FOR ... ENDFOR' loops
chapter.5:-- Conditionals. These can have several forms
chapter.5:-- Examples
chapter.5:-- Switch statements
chapter.5:-- Tracing
chapter.5:-- More on POP11 constructs
chapter.5:-- Vectors (Sometimes called 'strips')
chapter.5:-- Strings (Character vectors)
chapter.6:-- Recursion
chapter.6:-- An infinitely recursive procedure
chapter.6:-- Stopping the recursion
chapter.6:-- Making things clearer with TRACE
chapter.6:-- Recursing on a tree
chapter.6:-- Defining SEARCH_FOR
chapter.6:-- Recursion and local variables
chapter.7:-- Lists: an introduction
chapter.7:-- Exercise
chapter.7:-- ONEOF and DELETE
chapter.7:-- More exercises on lists
chapter.8:-- More list processing
chapter.8:-- Constructing lists
chapter.8:-- The use of [     ]
chapter.8:-- The use of "%" in list expressions
chapter.8:-- The use of ^ (the "up-arrow" or "hat" symbol)
chapter.8:-- The use of  ^^  (double "up-arrow" symbol)
chapter.8:-- The operation ::
chapter.8:-- The procedure CONSPAIR
chapter.8:-- The concatenator  <>
chapter.8:-- Using lists
chapter.8:-- Basic operations on lists
chapter.8:-- Exercises
chapter.8:-- Procedures and lists
chapter.8:-- Searching a list
chapter.8:-- Defining DELETE recursively
chapter.8:-- Iterating on lists
chapter.8:-- Using FOR ... IN ... DO .... with lists
chapter.8:-- Using FOR in [% ..... % ]
chapter.8:-- Iteration vs Recursion
chapter.9:-- MATCHES: an introduction
chapter.9:-- Exercise







Sep 13 00:15 1984  chapter.0 Page 3


chapter.9:-- The matcher arrow "-->"
chapter.9:-- Findroom revisited
chapter.9:-- List pattern matching
chapter.9:-- The matcher
chapter.9:-- Describing the shape of a list pattern
chapter.9:-- Using variables in a pattern specification
chapter.9:-- Retrieving details of the target list
chapter.9:-- Summary of match notations
chapter.9:-- MATCHing on a corpus of lists - the DATABASE concept
chapter.9:-- Adding and removing database items
chapter.9:-- What was removed?
chapter.9:-- Finding items in the database
chapter.9:-- Retrieving values from within an ITEM
chapter.9:-- Retrieving all the items PRESENT which match a pattern
chapter.9:-- Checking a set of patterns against the database
chapter.9:-- Forevery
chapter.p:-- POSSIBLE FURTHER ADDITIONS:
chapter.q:-- DCL or UNIX COMMANDS
chapter.z:-- ORDINARY VARIABLES
chapter.z:-- PROCEDURES
chapter.z:-- PRECEDENCES and OPERATORS
chapter.z:-- MACROS
chapter.z:-- SYNTAX WORDS
chapter.z:-- SYNTACTIC OPERATORS
chapter.z:-- NONIDENTIFIER WORDS
chapter.z:-- VED VARIABLES
chapter.z:-- VED PROCEDURES




































Sep 12 21:33 1984  preface Page 1


PREFACE


                  INTRODUCTION TO PROGRAMMING IN POP-11
                  =====================================
                              Aaron Sloman
                       Cognitive Studies Programme
                          University of Sussex



-- PREFACE ----------------------------------------------------

POP-11 is the core language of the Sussex University POPLOG system,
which also contains PROLOG (the logic programming language) and a
simplified version of LISP. POPLOG also contains a versatile screen
editor and other utility programs. The editor can be extended by the
user, and provides a general purpose, terminal independent, user
interface for screen-based programs.

The version of LISP in POPLOG (as of May 1984) is a reduced version
which is suitable for teaching, but does not contain all the
features of more widely used LISP systems (though it may be replaced
by Common Lisp later). However, POP-11 is similar in many respects
to LISP (though it is far more readable) and it does provide a fully
fledged research and development language.

POP-11 is the core of POPLOG in that the other languages are
implemented in terms of it. For users of POPLOG it is worth knowing
about POP-11, even if Prolog is the main language used. Knowledge of
POP-11 will make it possible to take full advantage of facilities
for extending and tailoring the editor VED to suit your own
requirements. Moreover, for certain kinds of programs POP-11 is more
convenient, and more efficient, than Prolog; e.g. programs which do
a great deal of arithmetic, string or vector manipulation, or
deterministic list processing.

This Introduction is illustrative rather than definitive:
alternative documents will be available providing more formal and
complete specifications of POP-11 language and library facilities.
It will be assumed that the reader already has some programming
experience in a conventional programming language, and will not be
reading about procedures, variables, arguments, results, loops,
stacks, etc. for the very first time. (A primer, for absolute
beginner programmers, may be available later.) Some sections may be
found difficult on a first reading and should be skimmed at first,
then re-read later.

-- Why POP-11? ------------------------------------------------

Why use POP-11 as a programming language rather than the better
known languages like BASIC, FORTRAN, COBOL and PASCAL? The principal
reason is that POP11 is a richer, more advanced language which
enables more ambitious programs to be written with less effort. For
teaching purposes, it enables the beginner to move quickly to more
interesting projects. Like PASCAL, it encourages the design of







Sep 12 21:33 1984  preface Page 2


well-structured, clear programs made of independently testable
parts. Like BASIC it is fully interactive, allowing full use of the
computer to simplify and accelerate development and testing of
programs. Unlike all these others it provides an elaborate but
friendly environment with many built-in aids to program development
and learning. It also provides powerful features not found in more
conventional languages, for instance the pattern matcher.

In particular the 'incremental compiler' and integrated screen
editor VED can enormously speed up program development time, as
compared with more conventional languages. In this respect it is
similar to the best LISP systems, though many people prefer the more
readable syntax of POP-11. The richer, more redundant, syntax seems
to make POP-11 a more suitable teaching language than LISP.

Like LISP, POP-11 can be used either as a main programming language
or as an efficient systems language on which to build higher level
tools, such as a logic programming language or an expert-system
shell.

Where a declarative style of programming is desirable, and
especially for tasks where there is a considerable amount of
depth-first searching for solutions to problems, Prolog will often
be a more suitable language. For this reason POPLOG includes a full
implementation of Prolog, compatible with the DEC-10 version of
Prolog. POPLOG allows programs in POP-11 and Prolog to be combined,
where a mixed style of programming is desirable. How this is done
will be documented elsewhere. (See the on-line help files on Prolog,
if you have access to a POPLOG system.) We deliberately left the
syntax of Prolog unchanged so that existing literature (e.g.
PROGRAMMING IN PROLOG by W. Clocksin and C. Mellish) could be used
as documentation. For users wishing to produce a more integrated mix
of POP-11 and logic programming, appropriate system-building tools
are provided within POP-11, though they will not be described in
this introduction.

Programs written in conventional languages (e.g. PASCAL, or C) may
be linked into the VAX VMS version of POPLOG. This facility will
later be extended to the UNIX version of POPLOG. For details see the
'REF EXTERNAL' file if you have access to an online version of
POPLOG.

-- A brief history --------------------------------------------

POP-11 is derived from POP-2, a language originally invented at
Edinburgh University for research in Artificial Intelligence. POP-2,
named after one of its inventors, is described in

    PROGRAMMING IN POP-2
    R. M. Burstall, J. S. Collins and R. J. Popplestone
    Edinburgh University Press, 1971

The original version of POP ran on an Elliot 4130 computer and is now
obsolete. It was transferred to the DEC-10 computer running the
TOPS-10 operating system in Edinburgh. Julian Davies, now at
University of Western Ontario, Canada, implemented an improved







Sep 12 21:33 1984  preface Page 3


version, called POP-10, in the early seventies. A new version of POP
for the DEC-10 called WPOP (WonderPOP), was implemented by Robert
Rae, with some help from Allan Ramsay, and became available in the
late seventies. It was also transferred to the TOPS-20 operating
system.

Steve Hardy implemented the first version of POP-11 in 1975. This
was a small system which ran on PDP-11 computers under the UNIX
operating system. It did not include all of POP-2, but had some
extra features instead, designed to make it easier to use,
especially for teaching purposes. In particular, the pattern
matcher, the autoloadable library mechanism and a large collection
of help and teaching files made it especially useful for educational
purposes, and several Universities and one school have been using it
for some time. Some of its features were incorporated into WPOP.
This version of POP-11 is now obsolete, and Sussex University is no
longer distributing it, but it is possible to obtain a version which
runs on PDP-11 computers with UNIX version 7, from Nottingham
University Psychology Department, who have kindly agreed to supply
it.

The second version of POP-11, available only since October 1981, and
mostly implemented by John Gibson, is much larger and has far more
facilities. It includes all the features of POP-2 and many more.
However, it will run only on a computer which has a large 'address
space', permitting processes well over three quarters of a megabyte
in size. So it will not run on small personal computers or the
PDP-11 family. However, as the price of hardware falls, we expect
that within a few years it will be possible for computers in the
home, in the office, and in schools to run programs of the size of
the POP-11 system, and larger, providing a very powerful tool for
program development, or for teaching computing.

The new POP-11, which is available only as part of POPLOG, runs on
VAX computers under VMS and Berkeley UNIX, on M68000 computers
(under Unisoft Unix), and the SUN.2 workstation running Berkeley
UNIX. Other implementations will be available later.

This introduction is based on the new larger version of POP-11. Many
of the examples will also work on the smaller PDP-11 version, but
not all. The smaller version does not include the screen editor.


-- The editor -------------------------------------------------

POPLOG contains a very powerful screen editor VED, similar in some
respects to EMACS, an editor developed at MIT. VED considerably
reduces the effort involved in developing and testing programs, or
writing documentation. Ideally, before using POP-11 you should learn
to use the screen editor.

However, details of this will vary according to which terminals are
available, so this document will not include information about the
editor. If you have access to a computer running POPLOG you should
ask for advice. There should be a 'TEACH file' available which will
show you how to use the editor on the terminals which are in use at







Sep 12 21:33 1984  preface Page 4


your site.

-- Interactive programming ------------------------------------

An important feature of POP-11 is its inherent ability to be used in
an 'on-line' mode. This means that commands in the language can be
given at any time: there is no division between a phase in which you
specify a program which is to be compiled, and a phase in which your
programs run. You can interleave additions to the program and
commands to run the program, using the same language and the same
running process for both. Thus you can define a procedure, then run
it to test it, then define a new procedure using the first one, then
run it, then define new procedures, etc. If you find a procedure
needs to be changed you can edit it without leaving pop-11 and the
new version will immediately be available without re-compiling other
procedures or re-linking your program. (Recompilation will be
required if the procedure had been declared as a constant for
efficiency.)

To make all this possible POP-11 contains an 'incremental compiler'
which is part of the system when programs are running. In most
languages the compiler is a separate program which runs to transform
your program into a form which the computer understands.

The use of an incremental compiler enables development and testing
to be far more rapid than with a conventional programming language,
such as Pascal or Fortran. Some languages with an interpreter offer
a similar facility (e.g. BASIC, some versions of LISP). The
advantage of an incremental compiler over an interpreter is that it
produces machine code, so that programs run faster. The advantage of
using an interpreter is that it reads in programs faster, and can
provide more flexible development aids.

Some argue that the interactive method of developing programs is
undisciplined. They assume that the best way to use a computer to
solve a problem is to:

    (a) specify the problem,
    (b) devise an algorithm to solve the problem
    (c) prepare a program embodying the algorithm
    (d) compile the program
    (e) run the program
    (f) go back to b or c to fix 'bugs'

This method of using a computer is ideal when

    (1) the problem is well defined
    (2) an algorithm can be devised easily
    (3) the user never makes a programming mistake
    (4) the user is a perfect typist

If the last two conditions aren't met then a slow and expensive
iteration of steps (c) to (e) must be performed. Often even the
first two conditions are not met. The problem may be well defined
but so complex that initial algorithms do not cover all cases, or
include inconsistencies or other errors, so that development and







Sep 12 21:33 1984  preface Page 5


testing involves a slow iteration through steps (b) to (e).
Sometimes even the problem isn't very well defined, for instance
where requirements for a program can only be developed as a result
of running a prototype in the intended environment. In that case the
iteration even involves step (a).

Whilst conditions (1) to (4) can be met for some cases (such as
routine data processing) they cannot be met for complex problems or
for inexperienced users. The use of an incremental compiler (or
interpreter) with an integrated editor and other program development
aids can enormously speed up the process of producing and testing
initial draft versions of programs. Since each new portion of
program can be tested quickly before the next portion is added,
without a slow process of re-linking, an environment like that of
POPLOG can encourage more thorough testing, leading to more reliable
programs, as well as saving programmer effort. This is sometimes
referred to as 'Rapid Prototyping'.

A consequence of using an incremental compiler is that there is not
really any such thing as a program in POP-11. In many languages a
program consists of a set of procedure or function definitions
(explained below) together with some commands to the computer, which
make use of those definitions; and the whole program has to be
specified completely before any commands can be obeyed. In an
interactive language like POP-11, you can go on indefinitely
interleaving running commands and defining new procedures or
modifying old ones. The commands and definitions may either be typed
in at the terminal or read in from a previously constructed file.

Moreover, unlike some languages, POP-11 does not require you to
separate your data and your programs. As we shall see, this provides
very powerful facilities, and in particular makes it possible to mix
factual assertions with other kinds of programming constructs.

-- Declarative and procedural languages ---------------------------

In some languages (e.g. Prolog) there are also ASSERTIONS, which can
be used to give the computer information, e.g. the information

    tom is the father of dick or, in Prolog:

    father(tom,dick)

In some languages it is possible to store generalisations, or
inference rules, like

    a father is a male parent, or
    x is the father of y if x is a parent of y and x is male,

or, in Prolog:

    father(X,Y):-parent(X,Y),male(X).

Such languages also allow the construction of QUESTIONS, such as
    who is the father of joe?








Sep 12 21:33 1984  preface Page 6


or, in Prolog:

    ? father(X,joe).

These are examples of the 'declarative' style of programming.

POP-11 is not based primarily on declarative programming, but there
is a subset, called the 'database package' which provides something
like assertions and questions. This package is built on more
primitive facilities, described in the next few chapters.

-- The need for procedures ------------------------------------

Advocates of declarative languages sometimes suggest that logic
programming should be used for all tasks. It is very natural,
however, for people to think in terms of instructions as well as in
terms of assertions and inference rules, and that is one reason why
we have provided both in POPLOG. For example, if someone asks you
the way to the station, you will not usually succeed in
communicating if you give lots of facts about where the station is
located. Instead you will probably give some instructions:
    go down that road until you come to the post office,
    then turn left and.....etc

Of course, if the questioner knows the town very well, it may
suffice for him to be told:
    the station is two blocks north of the post office.

However, in order to make use of that information he will have to
find some way of translating that into a plan for getting from where
he is to the post office. The plan will contain a set of
instructions about what to do when. Similarly, if you want the
computer to do something other than tell you the answers to factual
questions you often need to be able to give it instructions.

Even if all you are interested in is storing information and getting
answers to questions relating to the information, someone must first
tell the computer how to store information, and how to respond to
questions. Thus instructions of some sort are required as the basis
even for a purely declarative system.

-- Monitors -------------------------------------------------------

Another thing missing from POP-11 (and many other languages) is the
concept of a 'monitor' or 'demon': a program which waits until some
condition becomes true, and then immediately takes control and
carries out its instructions. Thus you cannot say in POP-11
something like

   'if ever the value of X becomes 99 then print out a warning'.

It is possible, using advanced facilities in POP-11, to extend the
language to allow such things. Such techniques will not be explained
in this introduction. There are a few special purpose monitors built
in to POP-11. For instance there is a procedure which is run
whenever an error occurs, and the user can define that to take







Sep 12 21:33 1984  preface Page 7


appropriate action. Also there is a user-definable procedure called
'interrupt' which is run whenever the user types an interrupt
character at the terminal (usually CTRL-C).

-- TEACH files and the VED editor -------------------------------

This document is not intended for absolute beginners. Usually
beginners do better to work on mini-projects at a computer terminal.
After a few weeks of practical experience, this document may prove
useful for revision purposes, and as a way of learning more about
POP-11 more quickly than by working through interactive 'teach
files'. In case the reader has access to a full POPLOG system, brief
information about these files is presented here.

TEACH files are read using the editor, invoked by the TEACH command.
Usually the first command is

        teach teach

which introduces the use of a Visual 200 terminal for reading teach
files. Different commands may be made available at sites where other
terminals are used, e.g. 'teach vt100' for the VT100 family of VDUs.

Since the editor allows two (or on some terminals more) files to be
visible at once on the screen it is often convenient to learn about
programming by having a teach file and a user file visible at the
same time. The teach files give information, examples of programs,
and suggestions for practical exercises.

The following interactive 'TEACH' files, provided with POPLOG
introduce the use of the editor VED, and its role in developing
programs.

        teach teach  (or teach vt100)
        teach ved
        teach vedpop
        teach lmr   (=load marked range)

For an absolute beginner, with no experience of programming, the
following TEACH files provide a succession of mini-projects:
        teach river
        teach respond
        teach river2
        teach riverchat

More general introductions to POP-11 facilities are provided by the
following, whose contents overlap considerably with this primer:
        teach define
        teach vars
        teach stack
        teach matches
        teach if
        teach database

An overview of currently available TEACH files is provided by
        teach teachfiles







Sep 12 21:33 1984  preface Page 8



-- The  HELP command -----------------------------------------------

The HELP command also invokes the screen editor, for reading files
which give relatively short descriptions of POP-11 facilities. The
following gives an overview of help files:

        help contents

If you do not have a terminal for which the editor has been made to
work, you can print out help files with the 'explain' command, e.g.:

        explain contents

There are many hundreds of other help files giving information about
error messages, system utilities, editor procedures, system
concepts, syntax, etc. For the Prolog and Lisp subsystems there are
also collections of help files, though not as many.

Readers will benefit from having access to a terminal from which
POPLOG can be run. This introduction therefore includes occasional
references to HELP or TEACH files which it may be useful to examine.
The reader who does not have access to POPLOG may ignore such
references.

-- The REF command ------------------------------------------------

The REF command may be used to access files which give a definitive
description of the POP-11 language, and its main system utilities:
for example:
    ref syntax
    ref arith
    ref compile

The file
    ref index

should tell you what is available. Beginners are not advised to look
at the REF files.

The rest of this introduction is a summary of the most basic
facilities in POP11. Other documents will be provided which describe
more advanced features, and which give more detailed information for
experienced programmers. We start in the next chapter by describing
in some detail an example which ilustrates how to use POP-11 as a
list-processing language with a fairly conventional syntax. Later
chapters provide more general definitions of the language and some
of its most useful facilities.

-- Acknowledgements --------------------------------------------

    This Introduction to POP-11 uses material produced over many
    years by colleagues in the Cognitive Studies Programme,
    especially Steve Hardy, Max Clowes and John Gibson. Useful
    suggestions and comments on earlier drafts have been made by
    various students and colleagues, including Graham Brown, Phil







Sep 12 21:33 1984  preface Page 9


    Philpot and Kim Hawkhurst of Systems Designers Ltd., Sak
    Wathanasin, and Laila Burrell-Davis.





























































Sep 12 22:22 1984  chapter.1 Page 1


CHAPTER.1

-- Introduction ---------------------------------------------------

This chapter presents a simple POP-11 program worked out in some
detail. Not all the details will be explained fully in this chapter.
More general and complete explanations will be given later. Ideally
the reader should try out the example on a computer running POPLOG,
but, for readers with some programming experience, it should be
intelligible without that. If some of the examples use a notation
which is hard to understand, looking ahead to the next chapter,
should make things clearer.

-- The ROOMS Exercise -----------------------------------------

Suppose you have the dimensions of a set of rooms in a building. You
may want to give these dimensions to POP-11 in the form of a list of
lists, and you may want POP-11 to print out various kinds of
information about the rooms, e.g. their perimeter, their floor area,
and their volume. To illustrate a number of basic features of POP-11
we'll define a collection of procedures to do this.

This is how you might give POP-11 information about the set of rooms.

First we tell POP-11 to declare a variable, called "rooms". Then we
construct a list of lists, giving for each room its length, breadth
and height in feet (or whatever units we have chosen to work with).
Finally we ask POP-11 to "assign" the list to the variable "rooms".

    vars rooms;

    [[room1 10 12 8]
     [room2 6 11 8]
     [room3 15 11 8]
     [room4 10 12 9]
     [room5 21 11 9]] -> rooms;

The occurrence of a pair of square brackets [ .... ] tells POP-11
that a list is to be constructed. Nesting the brackets tells POP-11
to make a list of lists.

POP-11's lexical analysis rules state that a word starting with a
letter may include a number, so that "room1" is accepted as a single
word, not a word and a number, whereas "1room" would be split into a
number and a word, i.e. 1 and "room".

We have declared "rooms" as a GLOBAL variable. That is, it is not
declared inside any procedure, unlike some of the variables to be
troduced below. This means that it can be referred to at any time,
and its value altered, or used, or printed out. E.g. we can give a
command to print it out, using the 'pretty-print' arrow ==>, thus:

    rooms ==>

and the computer prints out the value of the variable:








Sep 12 22:22 1984  chapter.1 Page 2


    ** [[room1 10 12 8]
        [room2 6 11 8]
        [room3 15 11 8]
        [room4 10 12 9]
        [room5 21 11 9]]

We are going to need a master procedure, which takes in a list of
lists like that above, then for each embedded list extracts the name
the length, the breadth and the height, and prints out the name
followed by the perimeter, area and volume. Let's call the master
procedure "display_data". We might define it as follows, using two
'local' variables 'list_of_lists' to hold the complete list of
information, given as input to the procedure, and 'room' to refer to
the data for each room in turn:

    define display_data(list_of_lists);
        vars room;
        for room in list_of_lists do
            display_room(room)
        endfor
    enddefine;

This tells POP-11 that a new procedure is to be defined. The first
line says that the procedure is to be called 'display_data', and
that when it runs it requires as input one object which, within the
procedure, will be called 'list_of_lists'. The object can be called
anything else in other places: the name, or variable, is private, or
'local' to the procedure. In fact we shall see that the object
called 'rooms' globally can be given as input to display_data.

The second line states that an additional local variable is required
by the procedure, to be called 'room'.

The next three lines use the imperative construction:
        FOR ... IN ... DO ... ENDFOR

which enables a program to take each element of a list and do
something to it. We have used the local variable 'room' to refer to
the first element of the list, then the second element of the list,
then the third element, etc. It doesn't matter how long the list is
-- each element will be referred to in turn.

The instruction
            display_room(room)

states that the procedure called 'display_room' should be applied to
whatever is referred to by 'room'. But display_room has not yet been
defined, and we shall have to define it later. The instruction will
be obeyed repeatedly, once for each element of the list called
list_of_lists. After the last one has been done, the procedure will
stop, since there is nothing after 'endfor', which signals the end
of the so-called 'for loop'. The word 'enddefine' merely signals the
end of a procedure definition.

We now have to define the procedure display_room. Look back at the
list of information assigned to the global variable 'rooms'. We want







Sep 12 22:22 1984  chapter.1 Page 3


display_room to be applied to each element of that list in turn.
Each element is a list of four elements, a word which is a room
name, followed by three numbers. So we define display_room to cope
with such a four-element list, as its input.

Using the built in printing procedure 'pr' and procedures we have
yet to define for computing perimeter, area and volume, we could
define the procedure like this:

    define display_room(list);
        ;;; print out information about the room given in list
        vars room_name, room_length, room_width, room_height;
        list(1) -> room_name;
        list(2) -> room_length;
        list(3) -> room_width;
        list(4) -> room_height;
        pr('INFORMATION CONCERNING: '); pr(room_name);
        pr(newline);
        pr('  perimeter is: ');
        pr(perim(room_length, room_width));
        pr(newline);
        pr('  area is: ');
        pr(area(room_length, room_width));
        pr(newline);
        pr('  volume is: ');
        pr(volume(room_length, room_width, room_height));
        pr(newline);
    enddefine;

(Note for experts: this could be defined considerably more
compactly, using the formatted printer, printf).

Let's look at the definition in detail. The first line says a new
procedure is being defined called 'display_room'. When it runs it
must be given one thing as input, which will be referred to as
'list' in the procedure. The second line is a comment, ignored by
POP-11.

The next line declares four additional names to be used in the
procedure, for local variables:
        vars room_name, room_length, room_width, room_height;

The next line is an imperative which says, take the first element in
the object called 'list' and assign it to the variable 'room_name',
which can then be used later in the procedure to refer to it:
        list(1) -> room_name;

Notice that the expression 'list(1)' can be used to refer to the
first element of a list. Similarly 'list(2)' refers to the second
element, and so on.

To avoid repeatedly having to extract the second element we use the
assignment arrow to store the result in a variable 'room_length',
which is used several times in the procedure. Similarly with the
remaining items of information.








Sep 12 22:22 1984  chapter.1 Page 4


In a later chapter we will see that there are alternative methods of
extracting elements of a list. In particular the four assignments in
the above procedure could be replaced by a single imperative
invoking the 'pattern matcher' using "-->", thus:

    list --> [?room_name ?room_length ?room_width ?room_height]

Line 8 of the definition has two imperatives, which print
information on the screen. The first prints the characters actually
given in the string, and the second prints the value of the variable
'room_name', which will be a word, e.g. "room1" or "room2", etc.
        pr('INFORMATION CONCERNING: '); pr(room_name);

The imperative:
    pr(newline);

Causes subsequent printing to be started on a new line.

A line like the following simply prints out a string, which can
include spaces:
        pr('  perimeter is: ');

The next imperative:
        pr(perim(room_length, room_width));

gives the values of "room_length" and "room_width" to a procedure
called 'perim' (yet to be defined, since it is not built in to
POP-11), and expects that procedure to produce one RESULT which is
then given as input to the procedure PR which will cause it to be
printed out. E.g. if room_length has the value 10 and room_width has
the value 12 then this should print out 44. Here we are using the
expression
    'perim(room_length, room_width)'

to refer to the number which is the perimeter of the room. So when
we define the procedure called 'perim' we have to ensure that it
produces a result, i.e. something which will be referred to by this
sort of expression.

The remainder of our procedure uses similar techniques, first using
the a procedure AREA, which has yet to be defined, then a procedure
VOLUME, also to be defined. Note that the line:
        pr(volume(room_length, room_width, room_height));

implies that VOLUME will be given three inputs, not two like the others.

Here is how you might define PERIM to calculate the perimeter. It
should take two numbers, add them, then multiply by 2 to get the
total perimeter, which is then the result of the procedure.

    define perim(len, breadth) -> total;
        (len + breadth) * 2 -> total
    enddefine;

The first line has two new features. First we are here defining a
procedure with two input variables 'len' and 'breadth', not just one







Sep 12 22:22 1984  chapter.1 Page 5


as before. (Note: we can't use 'length' for the first argument, as
that's already a name of a POP-11 system procedure. If we used
'length' we'd get a mishap message. Hence 'len'). Secondly the
procedure header ends with '-> total', which implies that this
procedure is to produce one result. What that result will be will
depend on what is assigned to the variable 'total' in the procedure.

The occurrence of '-> total' in the header is not itself an
assignment. It is merely an indication of how the variable "total"
is being used in the procedure. I.e. it is an 'output local'
variable, whereas "len" and "breadth" are 'input locals'. Although
the output local declaration looks like an assignment, it does not
cause the procedure to assign anything to the variable. Rather it
indicates that after the procedure is used there will be a 'result'
available, and the user must take care to assign something to the
variable "total" within the procedure, to be used as the result.

We can test the procedure thus, using "==>" to print out the result:

    perim(3,5) ==>
    ** 16

Actually, "==>", the 'pretty print' arrow is not needed for printing
out something as simple as a number. It is intended for printing
more complex structures, like lists of lists. So in this case, we
could use the simple print arrow "=>", thus:
    perim(3,5) =>
    ** 16

POP-11 has many built in procedures besides "+" and "*" which can be
used to create either complex expressions or complex imperatives.
More of them will be introduced later.


Similarly we can define AREA, using the multiplication symbol "*":

    define area(len, breadth) -> total;
        len * breadth -> total;
    enddefine;


and test it:

    area(8,12) =>
    ** 96

And volume:

    define volume(len, breadth, height) -> total;
        len * breadth * height -> total;
    enddefine;

and test it:

    volume(5,5,5) =>
    ** 125







Sep 12 22:22 1984  chapter.1 Page 6



Having defined all the required subsidiary procedures, we can now test
display_room, remembering that it requires a list of information about
one room:

    display_room([room17 5 6 7]);

And this command causes the following to be printed out:

    INFORMATION CONCERNING: room17
      perimeter is: 22
      area is: 30
      volume is: 210

We could arrange 'prettier' formatting, but for now we shall ignore
that. We can now run the master program on the list rooms, which we
created above. Just to check, we can print out the contents of the
list:

    rooms ==>
    ** [[room1 10 12 8]
        [room2 6 11 8]
        [room3 15 11 8]
        [room4 10 12 9]
        [room5 21 11 9]]

Then run the master procedure, giving it the list rooms as input:

    display_data(rooms);

which produces all the following printout:

    INFORMATION CONCERNING: room1
      perimeter is: 44
      area is: 120
      volume is: 960
    INFORMATION CONCERNING: room2
      perimeter is: 34
      area is: 66
      volume is: 528
    INFORMATION CONCERNING: room3
      perimeter is: 52
      area is: 165
      volume is: 1320
    INFORMATION CONCERNING: room4
      perimeter is: 44
      area is: 120
      volume is: 1080
    INFORMATION CONCERNING: room5
      perimeter is: 64
      area is: 231
      volume is: 2079

It is worth noting that only one of our procedures does any
printing, namely display_room. The procedures perim, area, and
volume produce RESULTS which they do not print out themselves. The







Sep 12 22:22 1984  chapter.1 Page 7


results are printed in display_room. They could have been used for
other purposes. For instance, we could use area to define volume, by
first computing the area, and then multiplying by the height:

    define volume(len, breadth,height) -> total;
        area(len, breadth) * height -> total;
    enddefine;

Here 'area(len,breadth)' produces a result, which is then multiplied
by the value of 'height' to produce the volume.

-- Exercise on the ROOMS example ------------------------------

This example illustrates features of POP-11 which need to be explained
in more detail later on. The following exercise should test your
understanding so far.

1. Modify the program so that in addition to the information shown above,
the dimensions of each room are printed out, before the perimeter.
You will need to work out which procedure should be modified, and how to
modify it. All the techniques required have already been demonstrated.

Some further questions for revision:

2. Explain what the 'for....endfor' form  achieves.

3. What is a local variable? What is the difference between an input
local and an output local? How are additional local variables defined?
(More on this in later chapters.)

4. In the left half of the imperative:
        area(len, breadth) * height -> total;

there are five expressions denoting numbers. What are they?

5. Explain the difference between '->' in a procedure heading and in an
assignment instruction. (More on this later.)


-- Searching for information ----------------------------------

In our example so far, we have used all the information in the list
rooms in a rather verbose fashion. If we wanted to find information
about a particular room, e.g. room3, we could use our knowledge of
the order of the items in the list rooms, and get the third element and
give it to display_room, using the expression 'rooms(3)' to denote the
third element of the list called 'rooms', thus:
    display_room(rooms(3));

    INFORMATION CONCERNING: room3
      perimeter is: 52
      area is: 165
      volume is: 1320

But if we don't know the order in which information is stored, then
we can define a procedure to search in the list for information about







Sep 12 22:22 1984  chapter.1 Page 8


the room required. We want a procedure called findroom which
    a. takes a room name and a list of room data as input
    b. produces the data for the given room as its result

We can do this, using techniques already illustrated, by examining each
piece of room information in turn until we find one whose first element
is the name of the required room. At that point we can stop the search.
If we get to the end of the list without finding the relevant room,
produce a mishap message.

    define findroom(name, list_of_lists) -> data;
        ;;; search list_of_lists for one starting with name
        for data in list_of_lists do
            if data(1) = name then
                return();       ;;; i.e. stop the procedure
            endif;
        endfor;
        ;;; produce a mishap message
        mishap('DATA NOT FOUND', [^name ^list_of_lists])
    enddefine;

We have again used the 'for <item> in <list> do <action> endfor'
format. This time the <action> is a conditional imperative, of the
form:

    if <condition> then <action> endif

Later we'll meet alternative forms of conditionals. The action in
this case is simply to 'return', i.e. to jump to the end of the
procedure. Because 'data' is specified as an output local, the value
of 'data' which made the condition
             data(1) = name
 true will be the result of the procedure. In other words the result
will be the list of information about the room with the name
specified.

We can test findroom as follows using the word-quote symbol '"' to
say that the first input given to findroom is to refer to itself. We
use the print arrow '=>' to print out the result produced by
findroom.

    findroom("room3", rooms) =>
    ** [room3 15 11 8]

    findroom("room5", rooms) =>
    ** [room5 21 11 9]

And if we give it a room which can't be found we get a mishap
message:

    findroom("room17", rooms) =>

    ;;; MISHAP - DATA NOT FOUND
    ;;; INVOLVING:  room17 [[room1 10 12 8] [room2 6 11 8] [room3 15 11 8]
         [room4 10 12 9] [room5 21 11 9]]
    ;;; DOING    :  findroom compile







Sep 12 22:22 1984  chapter.1 Page 9



This message is produced by the line in our procedure definition
which invokes the built in procedure called "mishap" (which is
actually re-definable by the user, if different error handling is
required.)

At this stage it may be difficult to understand everything in the
definition of findroom. After reading later chapters on list
processing, conditionals, and looping constructs, it may be useful
to look back at this chapter, which may then make more sense.

Findroom is sufficiently general to be given different lists of
rooms on different occasions. We can use it to define a procedure
called 'find_and_show' to print out the data concerning a given
room. It uses findroom to dig out the list of data to give to
display_room for printing.

    define find_and_show(name,list);
        display_room( findroom(name, list) );
    enddefine;

Notice that the two items given as input to find_and_show are simply
handed on as input to findroom. It produces a result which is used as
input for display_room. The same thing could be said less compactly,
though perhaps more clearly, by using a local variable to hold the
result produced by findroom.

    define find_and_show(name,list);
        vars room;
        findroom(name, list) -> room;
        display_room(room);
    enddefine;

To test the procedure, we can type:
    find_and_show("room2",rooms);

Which produces the following printout:

    INFORMATION CONCERNING: room2
      perimeter is: 34
      area is: 66
      volume is: 528

Note that find_and_show does not produce a result (it has no output
local) and so we don't use the print arrow in our test instruction.
Instead the semi-colon terminates the imperative.

-- Finding several rooms --------------------------------------

If we wanted to dig out information about not just one room, but
about several, then we could define a procedure to take a list of
the names of wanted rooms, as well as the master list, and search
for each required room in turn, using find_and_show:

    define find_and_show_all(namelist, list);
        for name in namelist do







Sep 12 22:22 1984  chapter.1 Page 10


            find_and_show(name, list)
        endfor
    enddefine;

Testing it, using our global list called 'rooms':

    find_and_show_all([room2 room4], rooms);

which prints out:

    INFORMATION CONCERNING: room2
      perimeter is: 34
      area is: 66
      volume is: 528
    INFORMATION CONCERNING: room4
      perimeter is: 44
      area is: 120
      volume is: 1080

You may already be able to see that we can define procedures which
are much more flexible than this. In this example we always dig out
the same sort of information, even though it may be about different
rooms. We could define procedures which produce different sorts of
information. E.g. given a width, find all the rooms with that width,
or find all the rooms which have a given length and height, etc.
Later we shall see that use of the POP-11 matcher would make this
sort of flexibility much easier to achieve.

-- Exercises --------------------------------------------------

Before attempting these exercises, some readers may find it helpful
to read the next chapter.

1. Modify the above examples to define a procedure which instead of
being given the name of a room is given its length. It should print
out information about all rooms with that length.

2. The procedure find_and_show_all could be very inefficient. For
each room name it initiates a new search down the list, using
find_and_show. If the list of room data is very long, this could be
very wasteful. Try defining a new version of find_and_show_all which
is essentially like findroom, but modified to take a list of names
instead of just one name. Further it would not have an output local,
since it would print relevant information instead of producing a
result. Two further modifications of findroom will be needed. The
call of mishap at the end should be removed, and the conditional
            if data(1) = name then
                return();       ;;; i.e. stop the procedure
            endif;

will need to be replaced by something equivalent to the following,
(which is not POP-11):
    if data(1) is a member of the list of names then
        display_room(data)
    endif;








Sep 12 22:22 1984  chapter.1 Page 11


There is a procedure called 'member' in the POPLOG system which
takes an item and a list and produces the result TRUE if the item is
in the list, false otherwise. So
    member("room4", [room2 room4 room17])

would be an expression denoting TRUE, whereas
    member("room5", [room2 room4 room17])

would denote false. You could use a conditional starting something like:
    if member(data(1), namelist) then

3. If the procedure called 'member' did not already exist in POP-11
you could define it using concepts already illustrated. Try defining
a procedure called 'iselement' which takes an object and a list of
objects, and searches down the list using "=" to see if the given
object is the same as an element of the list. If so stop searching
and produce the result TRUE, using the imperatives:
        true -> result;
        return();

If you get to the end of the list without finding the given object then
the last action would be
        false -> result;

The search process could use the 'for ... endfor' syntax. When
tested your procedure should behave like this:

    iselement("cat", [mouse cat dog]) =>
    ** <true>


    iselement("pig", [mouse cat dog]) =>
    ** <false>

    iselement(4, [a 1 b 2 c 3 d 4 e 5]) =>
    ** <true>

    islement(99, []) =>
    ** <false>

Notice that in POP-11 a procedure like member (or iselement) can be
defined to take any sort of object and any sort of list of objects.
In a 'typed' language like PASCAL you would have to define one
version of the procedure for lists of numbers, another for lists of
words, another for lists of lists, etc.

In the next chapter we shall give a somewhat more formal
introduction to POP-11, defining in more general terms some of the
constructs illustrated here.














Sep 12 21:35 1984  chapter.2 Page 1


#E
CHAPTER.2


-- The POP-11 language -------------------------------------------

A programming language has two main aspects: the symbolic
structures, and their meanings, often called the syntax and the
semantics of the language.

In a language like POP-11 the meanings are of different sorts: in
particular, EXPRESSIONS refer to OBJECTS, IMPERATIVES to ACTIONS.
Defining POP-11 involves specifying which sorts of objects there
are, and what sorts of actions can be performed on them, and
learning the syntax for creating or referring to objects and for
specifying or performing actions.

Some actions are concerned entirely with processes within the
computer, like re-ordering a list of names. Others may be concerned
with information flowing into or out of the computer, e.g. text read
in from or printed out to the terminal, or a file. Most of this
introduction is concerned with the former.

-- Some POP-11 data-types -------------------------------------

Objects referred to in POP-11 include numbers, words, strings, lists,
and others explained later. There are standard notations in POP-11
for referring to such things:

Numbers:
    Integers:   66   99876789   -66

    Decimals:   88.532   1.2345e3 (=1234.5)   123.4e-3 (=0.1234)

Words:
    "cat"   "ninety"   "fast_back"   "+"   "+**+"

Strings:
    'cat'   'ninety'   '66'   'a string with spaces ++**@@@@'

Lists:
    [a list of words]     [ [a list] [of lists] [66 77]]

Here is a list containing words, numbers and lists:

    [name [joe bloggs] age 33 job [university teacher] sex male]

POP-11 also provides several other data-types, described later,
and allows the user to define new ones.

-- Some POP-11 actions ----------------------------------------

The actions, or processes are produced by imperatives in POP-11.
Actions may create objects, compare them, search for them, store
them, print them out, etc.
There are many forms of imperatives for different purposes. For







Sep 12 21:35 1984  chapter.2 Page 2


example, here is a command to print out the sum of two numbers:
    99 + 66 =>
which prints out
    ** 165

And here is a command to store a number in the 'variable' num --
an assignment:
    66 -> num;

Read '->' as 'goes to'. Unlike most languages, assignments in POP-11
go from left to right: first specify the object to be assigned, then
say where it is to be stored.

Thus the syntax of POP-11 allows for both EXPRESSIONS, which refer
to objects, and IMPERATIVES, which tell the computer to do
something. We can view all expressions as imperatives instructing
POP-11 to create or find the object referred to. Thus 'imperative'
is the more basic concept in this sort of language.


-- Built in and user-defined procedures ------------------------

POP-11 has many different sorts of built in instructions, and new
ones can be defined by the user. In POP-11 these are called
'procedures'. ('function' is used in LISP.) Procedures are defined
in POP-11 by specifying a name, and instructions to be obeyed when
the name is used in an imperative.

There are different ways of putting instructions together. One
common form is just a sequence of things to be done one after
another. Another form is a conditional which specifies that what is
to be done may depend on the result of one or more tests. Another
common form is a loop in which a set of instructions is obeyed
repeatedly, until some terminating condition is reached.

The ability to use 'conditional instructions' is one of
the things which makes it possible for a computer to be intelligent.

-- Errors and error messages -----------------------------------

To err is human, and the machine will print out 'mishap' messages.
E.g. if you leave out the "+" between two numbers:

    6 6 =>

    ;;; MISHAP - MSEP: MISSING SEPARATOR (eg semicolon)
    ;;; INVOLVING: 6 6
    ;;; DOING    : compile

The 'code' before the colon in the top line ('MSEP' in this case),
is a key to a help file which will explain in more detail what this
sort of error message is about. You can examine the relevant
explanatory file with the command

    help msep








Sep 12 21:35 1984  chapter.2 Page 3


This will invoke the POP-11 HELP facility which uses the screen
editor VED. It should only be used after you have learnt to use the
screen editor. Alternatively the following command will simply print
out the explanatory file on the terminal:

    explain msep

-- Syntactic and semantic errors ------------------------------

Some mistakes are 'syntactic', or 'compile time' errors: you have
not typed what POP-11 regards as meaningful instructions. The
'MISSING SEPARATOR' error is an example. 'Semantic errors', or 'run
time' errors occur when POP-11 understand the instructions, but
discovers in the course of obeying them that something is wrong,
e.g.

    "one" + "two" =>    ;;; POP-11 doesn't understand English!

    ;;; MISHAP - NUMBER(S) NEEDED
    ;;; INVOLVING:  one two
    ;;; DOING    :  + compile

POP-11 understood that it was being told to add two WORDS. So it
asked the procedure "+" to add them. This procedure checked what it
was given as inputs, and then invoked the error handler to print
this message. Notice that the DOING line mentions that it was
actually doing "+", as well as doing "compile". In the previous case
it was only doing compile.

In order to do anything POP-11 has to 'compile' what you type in,
i.e. translate your commands into machine instructions, which are
then obeyed. So POP-11 invoked compile, which invoked the "+"
procedure to do something. Thus it was in the middle of doing both
"+" and (temporarily suspended) "compile", when the error occured.
So:

    POP-11 runs compile
                compile calls +
                    + calls the error procedure 'prmishap'

After the error it goes back to doing whatever it was doing before
you typed the command which caused the trouble.

(Note for experienced programmers: there is an 'error-break'
facility which enables the user to take control when an error or
other interrupt occurs. This is done by re-defining either a
procedure called PRMISHAP or a procedure called INTERRUPT, or both.
The procedure POPREADY can be used for the latter.)

-- Comments in POP-11 programs --------------------------------

You will find that inserting short explanatory passages (usually
only a line) helps explain a piece of POP-11 program. To facilitate
that POP-11 skips over the remainder of any line that contains three
semi colons thus








Sep 12 21:35 1984  chapter.2 Page 4


        ;;; This is a comment
        3 + 5 =>    ;;; Print sum of 3 and 5
        ** 8

    /*
    Longer comments, going over several lines can be enclosed
    between the comment brackets "/*" and "*/", just like this
    paragraph.
    */

All such text will be completely ignored by the POP-11 compiler. We
occasionally insert comments in one of these two formats in examples
in this primer. E.g. the previous section on mishap messages
included an 'end of line comment'.

-- Expressions: some examples ---------------------------------

Before explaining how to define procedures, we need to explain some
of the building blocks - expressions and imperatives, already
mentioned.

We need expressions to tell POP-11 which objects to manipulate.
Among the objects we can manipulate are numbers, words and lists.

Here are some expressions in POP-11 which denote numbers:
    3
    999
    999 + 5
    (999 + 5) - 666

Here is an imperative which contains an expression '999 + 5' and,
using the so-called 'print arrow', tells POP-11 to print out what
the expression denotes
    999 + 5 =>

That will make the computer print out
    ** 1004

where the two asterisks '**' are produced by the command '=>' to
indicate that what follows was printed by the computer.

Here is an expression denoting a list of words
    [a list of five words]

Here is a list of three lists of words

    [ [a dog] [a big cat] [a silly old man] ]

Now a list of numbers:
    [1 2 3 4 5 6 7 8 9]

You can mix words and numbers:

    [1 2 3 4 5 6 7 8 9 10 jack queen king]









Sep 12 21:35 1984  chapter.2 Page 5


If you want to refer to a list containing a single word in POP-11
you can do it with the following sort of expression:
    [elephant]

This denotes a list containing the word "elephant". More precisely,
it is an instruction to POP-11 to create a list containing just the
word "elephant". If you type the same thing again it will create
another similar list, with the same word in it.

If you wish merely to refer to the word, then use the double quote
symbols, e.g.:
    "elephant"

A program might use a list of words rather than a single word if,
for example, it has to store someone's forenames, and you can't tell
in advance whether there will be only one forename, or several
forenames. E.g.
    [John Jones]
    [Mary Sue Wilikins]
    [Liberace]

Since a list can contain arbitrarily many words, using lists will be
more flexible in that case. Later we shall see many examples of the
use of lists to group things together.

To sum up: an expression is a piece of POP11 which refers to some
object. It may be an object which always exists, e.g. the number 99,
or it may an object created as a result of the use of the
expression, e.g. a lists of numbers. In order to do something to
such an object it is necessary to use an imperative which tells
POP-11 to perform some action.

-- Imperatives: some examples ---------------------------------

Printing
========
We have already met the use of "=>" in an imperative to print
something out. For example the following prints out a list of words:
    [tom dick harry] =>
    ** [tom dick harry]

Assignment
==========
Another very common form of imperative is an 'assignment', using the
assignment arrow '->'. Here is how you assign a number to be the
value of the variable 'x'.

    99 -> x;

    99 + 5 -> y;

In both cases the left hand side is an expression which denotes a
number. The whole thing says: 'take the thing denoted by the
expression on the left, and make the thing on the right (the
variable 'x' or 'y'), refer to it from now on. Thus, in the second
example 'y' will refer to 104. This can be tested with another







Sep 12 21:35 1984  chapter.2 Page 6


imperative:
    y=>
    ** 104

Normally an imperative which doesn't end with the print arrow "=>",
must end with a semi-colon. Later we'll see that if an imperative is
embedded in a larger structure it doesn't always need the
semi-colon.

A few more examples of assignments:
To give the variable X the value 33 do:

    33 -> x;

to give the variable Y twice the value of X do:

    x + x -> y;

OR

    (x + x) -> y;

Notice the difference between using the variable on the left and on the
right of an assignment. On the left its existing value is USED. On the
right a new value is SET, or assigned. So to assign the value of X to Y
do
    x -> y;

To assign a list of numbers to LIST1 do something like:

    [ 1 2 3 4 5 ]  -> list1;

To assign a list of words to LIST2:

    [cat dog mouse elephant] -> list2;

To assign a list like LIST1 but in reverse order to X, do:

    rev(list1)  -> x;
    x  =>
    ** [5 4 3 2 1]

Declarations
============
These may be used to introduce new variable names. E.g.
    vars x, y;

This 'declares' to POP-11 that you wish to use the names 'x' and 'y'
as names for objects. (The comma is optional.). Any number of
variables may be introduced in one declaration. The same syntax is
used for introducing both global variables and local variables,
explained below.

NOTE: for experienced computer scientists.
    Like many implementations of the language LISP, POP-11
    variables use dynamic scoping and shallow binding.







Sep 12 21:35 1984  chapter.2 Page 7


    There is a type of declaration which can be used only within a
    procedure definition (see below) to specying that a variable is
    to be a 'lexical' variable, i.e. lexically scoped. The format
    for this is to use 'lvars' instead of 'vars', e.g.

        lvars num, lista, listb;

    declares three lexical variables. The difference between lexical
    and non-lexical scoping is rather subtle and will not be
    explained here. Suffice it to say that for most purposes
    programs will run more quickly and be less liable to errors if
    the variables which are local to a procedure are declared as
    lexical. (However, this will not work if the variables are to be
    used by the pattern matcher, explained in a later chapter.)
    In some Poplog implementations some of the lvars will allocated
    to registers. E.g. on the VAX, the first two lvars in each
    procedure are treated as names of registers, for efficiency.

There are, in fact many different sorts of declarations, used for
telling the POP-11 compiler that a symbol is to have special
properties, but they will not be discussed in this primer. (In the
full POPLOG system they are described in the HELP VARS, and REF
SYNTAX files.)

Note: POP11 is a lower-case language, and most system words use only
lower case. Users may declare variables using upper or lower case.
So:

    vars cat, Cat;

declares two different variables.

Occasionally we use upper case in our examples, where this aids
clarity.

As we shall see, variables may be declared locally, in a procedure,
or globally.

Variables may be used without being declared. This is equivalent to
declaring them globally, except that POP11 prints out a warning
message.

    3 -> xx;
    ;;; DECLARING VARIABLE xx       (Printed by POP-11)

If you declare a variable which is already part of the POP11 system
vocabulary, for example:

    vars define;

you will get a mishap message:
    ;;; MISHAP - IDW: ILLEGAL DECLARATION OF A WORD

Procedure definitions.
======================
As an example, here is the definition of a procedure called 'silly'







Sep 12 21:35 1984  chapter.2 Page 8


which takes one thing as input and then prints it out twice using
the print-arrow:

    define silly(item);
        item =>  item =>
    enddefine;

This contains an implicit global declaration of 'silly' as the name
of a variable, whose initial value is the procedure defined here. It
also contains an implicit declaration of 'item' as a local variable
of the procedure. (This will be explained more fully below.)

Procedure calls
===============
The definition of silly included two imperatives. The instructions
are not obeyed when POP-11 reads in the definition. Rather, a
procedure is created in which the instructions are stored for FUTURE
use. So we need a means of telling POP-11 to actually obey the
instructions. We also need to tell POP-11 what it should treat as
the 'item' to be printed out twice. This is done by writing the name
of the procedure, followed by parentheses specifying the inputs
(arguments) of the procedure, if there are any:

    silly([mary had a little lamb]);

Given the above definition of the procedure silly, this would cause
the following to be printed out:

    ** [mary had a little lamb]
    ** [mary had a little lamb]

Terminology varies. We may say the procedure is 'run', 'invoked',
'obeyed', 'executed', 'applied'. These all mean roughly the same,
though some may be more natural in certain contexts. For instance we
say the procedure silly was 'applied' to the list [mary had a little
lamb].

Some procedures take no arguments. They are run without being
applied to anything. One such is sysdaytime, which produces a string
of information about date and time. We can run it, with no inputs,
and use the print arrow to print out the resulting string. Note the
empty parentheses:

    sysdaytime() =>
    ** Fri Jun  8 21:23:08 1984

Notice that all the imperative requesting that POP-11 do something
ended with either a semi-colon or a print-arrow. POP-11 will not
start executing the imperative until it finds the semi-colon or the
print-arrow, since until then it is not sure whether the imperative
is complete or some additional portion is to be added. This is
because POP-11 allows a single command to be spread over several
lines. (Individual lines and whole commands can be as long as
you like: newlines and spaces are equivalent in POP-11).

POP-11 contains many built in procedures, which can be used in







Sep 12 21:35 1984  chapter.2 Page 9


imperatives. By defining their own procedures, users can extend
the range of imperatives and expressions in POP-11. (A list of built
in procedures is included in the list of system words given at the
end of this Introduction.)

-- Using infix operators ------------------------------------------

In the imperative

    3 + 4 =>

the symbol "+" acts as the name of a built-in procedure to be applied
to the numbers 3 and 4. The symbol "+" is called an 'infix operator'
because you can run the procedure by writing the name between the
intputs, although the following would work just as well:

    +(3, 4) =>
    ** 7

Just as "+" can be used for addition, "*" can be used as an infix
operator for multiplication. So:
    3 * 5 =>
    ** 15

    999 * 999 =>
    ** 998001

In a later chapter we show how users can define their own infix
operations.

-- Procedures which produce results -------------------------------

Just as procedure definitions can extend the range of imperatives in
POP-11, so can they also be used to extend the range of expressions.
For example, here is a procedure which, when given two numbers,
produces another number which is got by doubling the first two then
adding.

    define doublesum(num1, num2) -> total;
        num1 + num1  + num2 + num2 -> total;
    enddefine;

There are several different formats for procedure definitions, but
we have now seen the two most common -- one which produces no
results and one which produces a result:
    define <name> (<arguments>);
        <body of procedure>
    enddefine;

    define <name> (<arguments>) -> <name of result>;
        <body of procedure>
    enddefine;

Given the above definition of doublesum, the expression

    doublesum(2,3)







Sep 12 21:35 1984  chapter.2 Page 10



invokes the procedure , applying it to the numbers 2 and 3.
Since the procedure produces a result, i.e. 2 + 2 + 3 + 3 = 10, we
say that the whole expression 'denotes' the number 10.

Similarly
    doublesum(4,5)

is an expression which denotes the number 18. Did you notice that
DOUBLESUM is effectively the same procedure as PERIM, defined in
chapter 1, even though its name, and the names of the variables it
uses, are different? Convince yourself of the equivalence by
studying them closely. Although they are different internally, they
take the same sorts of arguments, and produce the same sorts of
results.


Generally, if a procedure produces a result then its name can be
used to form an expression, by supplying it with appropriate
argument expressions.

The arithmetic procedures "+" and "*" also produce results, and so
by applying them to arguments we can form expressions denoting
numbers:

    3 + 5

    3 + 5 * 2

The latter denotes 13, since the multiplication is done before the
addition, for reasons which will be explained later.

When we define a procedure we specify whether it needs to be given
any input and whether it produces any 'results'. For example the
procedure silly was defined so as to take one thing as its input. We
say it takes one 'argument'. Doublesum was defined to take two
arguments, and produce one result. Silly printed things out, using
the print arrow, but that is not the same as producing a result.

When a procedure produces a result, the result is available for use
by other procedures in the computer. But if something is printed out
on the screen, this can't be used by other procedures, since the
computer cannot see what is on the screen. Instead, results are
stored in a special portion of the computer memory called the
'stack'. This will be explained in more detail later. When a result
is produced it can be assigned to a variable, or used as input to
another procedure.

    vars x;
    3 + 4 -> x;                 ;;; assign the result of + to x.

    silly (3 + 4);              ;;; result of + is input to silly.

The word "output" can be ambiguous: referring either to something
printed out, or to a result left by a procedure on the 'stack'.
(Later we explain what the stack is and how it works.) When we talk







Sep 12 21:35 1984  chapter.2 Page 11


about a procedure producing output the context should make clear
which is intended: printing something out, or leaving a result on
the stack.

The arithmetic procedures + and * each take two arguments (two
numbers) and produce a result, one number which is left on the
stack.

-- Two forms of print-arrow ---------------------------------------

POP-11 provides several means of printing information so that it
goes to the terminal, into a file, into the editor buffer, or into a
data-structure.

One of the most commonly used is the print-arrow, which we have seen
previously. This comes in two versions.

    => (ordinary print arrow)
        This prints everything 'on the stack', preceded by '**', unless
        called from inside a procedure, in which case it prints out only
        the top item of the stack, preceded by '**'.
        The stack is explained below. Roughly think of => as printing
        out the 'unused' results of previously executed procedures.

    ==> (pretty-print arrow)
        This prints out only ONE object. If the object is a list or a
        vector, then if printing it out would take more than one
        line, the object is printed in a special format using
        indentation to make its structure clearer.

Examples:

    33 + 66 =>
        ;;; print sum of 33 and 66, preceded by two asterisks.
    ** 99

    234 + 22  >  33 * 66  =>
        ;;; is 234 + 22 bigger than 33 times 66?
    ** <FALSE>

    X + 5 < Y =>
        ;;; is the sum of X and 5 less than Y?
        ;;; X and Y should have numbers as values.

    99 + 5 = 95 + 9  =>
        ;;; is 99 + 5 equal to 95 + 9?
    ** <TRUE>

    X = Y  =>
        ;;; does X have the same value as Y?

    X =>
        ;;; print out the value of X.

    10 // 3 =>
        ;;; prints out remainder and quotient







Sep 12 21:35 1984  chapter.2 Page 12


    ** 1 3

    [a [nested list of several words] and [another nested list
               of several words] too long to print easily] =>
    ** [a [nested list of several words] and [another nested list of
            several words] too long to print easily]

Compare the use of the pretty print arrow:
    [a [nested list of several words] and [another nested list
               of several words] too long to print easily] ==>
    ** [a [nested list of several words]
          and
          [another nested list of several words]
          too long to print easily]

When lists are deeply nested the printout from => can be a little
confusing, so it is then best to use ==> instead. You can in fact
always use '==>'. This is especially useful for a list of several
lists of similar format. E.g.: Make a list of lists of information
about people

    [
        [the mother of mary is suzy]
        [the father of mary is joe]
        [the mother of joe is miranda]
        [the father of joe is fred]
    ] ==>

Which causes the following to be printed out neatly:
    ** [[the mother of mary is suzy]
        [the father of mary is joe]
        [the mother of joe is miranda]
        [the father of joe is fred]]

Whereas using => would have produced:

** [[the mother of mary is suzy] [the father of mary is joe] [the mother
         of joe is miranda] [the father of joe is fred]]

Note that => or ==> can be used to terminate an imperative without a
semi-colon.

-- Other printing procedures --------------------------------------

POP-11 provides a number of built in procedures for printing things
in a more controlled format than the print arrows. In particular, the
procedures PR and SPR print things without starting a new line, or
printing the asterisks '**'. The difference is that SPR prints a
space after printing its argument. So:
    pr("cat"); pr("mouse"); spr("hat"); spr("coat");
    catmousehat coat

Using the built in printing procedures, it is fairly easy in POP-11
to define your own procedures to print things out in whatever format
you like. More information about printing can be found in the
online file HELP PRINT.







Sep 12 21:35 1984  chapter.2 Page 13



-- Conditionals and conditions ------------------------------------

One of the things which makes computers so versatile is their
ability to decide for themselves what to do, instead of always doing
exactly what they are told. This often depends on the use of
conditionals, i.e. commands to do something if something is true.
POP-11 includes conditionals, of which a simple form would be

    if <condition> then <imperative> endif

for example,

    if x = 10 then x => endif;

which will print out the value of x, if it is 10, and do nothing
otherwise. Conditionals must include a 'condition' between 'if' and
'then', and may include any arbitrary pop11 imperative (which may
be a sequence of imperatives) after 'then'. (They may also be typed
over several lines.)

A condition is an expression whose value is either the object TRUE
or the object FALSE. These are called 'boolean' objects, of which
there are exactly two in POP-11. (They are named after George Boole
the logician.) There are two built in system names, "true" and
"false" which refer to the booleans. They print out as <true> and
<false>.

    true =>
    ** <true>

    false =>
    ** <false>

In the above conditional, the expression 'x = 10' could serve as a
CONDITION, because its value will be either true or false. E.g.
    vars x;
    99 -> x;
    x = 10 =>
    ** <false>

This in turn is because the infix operation symbol '=' denotes a
procedure which always returns a BOOLEAN. It compares its two
arguments, and if they are the same the result is true, otherwise
false. (Strictly speaking "=" is more complex than this, since the
type of comparison it performs can be made to depend on the types of
objects performed, as explained in HELP CLASSES and REF KEYS.)

-- Predicates -----------------------------------------------------

Any procedure whose result is always a boolean is called a
PREDICATE. Besides "=" there are several other predicates which
compare two numbers and produce a boolean, e.g. ">", "<".

    x > 10  =>
    ** <true>







Sep 12 21:35 1984  chapter.2 Page 14



Some predicates take a single argument, for instance RECOGNISER
predicates, like isinteger, isword, isprocedure, islist, and several
more.

    isinteger(99) =>
    ** <true>
    isword(99) =>
    ** <false>
    isword("isinteger") =>
    ** <true>
    isprocedure(isinteger) =>
    ** <true>
    isprocedure("isinteger") =>
    ** <false>

We have so far said that a condition is an expression whose result
is a boolean.To be more precise, POP-11 is defined to treat anything
other than false as if it were true, between 'if' and 'then' (and in
similar contexts explained later), so a condition may produce a
result other than true, which is sometimes convenient. Similarly
predicates may produce either the result false, or something else,
representing true.

-- Summary of syntactic roles -------------------------------------

Portions of POP-11 program described so far may be classified as
follows -- the diagram is incomplete, and may be expanded by looking
back over this chapter:

                            imperatives
                                |
                _____________________________________________
                |                    |             |         etc...
            expressions           assignments   declarations
                |                               |          |
    __________________________      variable declarations  |
    |       |      |      |                                |
numerals    |      |  conditions             procedure definitions
       quoted words|
                   |
           list expressions

-- Word-formation rules in POP-11 ---------------------------------

We have so far assumed that we can treat POP-11 programs as made of
numbers and words which can be combined to form expressions,
or imperatives, or sequences thereof. But what is actually typed in,
or read in from a file is a sequence of characters. For instance the
following is a sequence of five characters, which has to be broken
up into four items, the number 3, the word "+" the number 5 and the
word "=>" :

    3+5=>

POP-11 applies quite complex rules to decide how to divide up the







Sep 12 21:35 1984  chapter.2 Page 15


stream of characters into meaningful chunks. For instance, if you
type:
    [a little list,and,6*5]

this is read as 11 items:
    [  a  little  list  ,  and  ,  6  *  5  ]

and in fact they will be interpreted as an instruction to build a
list containing nine items: seven words and two numbers.

To do this POP-11 needs rules saying which sorts of characters can
be joined up with which, since you don't have to use spaces to
separate things. Besides things like spaces, tabs and newlines,
which are normally ignored by POP-11, there are the following types
of characters:

Numeric:        0 1 2 3 4 5 6 7 8 9

Alphabetic:     a b c d e f g  ...  z
                A B C D E F G  ...  Z

Signs:          ! ## $ & + - : < = > ? @@  \ ^ | ~ / *

Underscore:     _

Separators:     ; " % ( ) , .  [  ]  {  }

String quote:   '

Character quote: `

POP11 combines a letter followed by a series of letters and numbers
into a single word. But if you start with a number, then as soon as
a non-number is reached (e.g. the "l" in "1list") POP-11 assumes
that it should insert a break. I.e. the text is separated into a
number followed by a word. This can be shown by typing in the
following instructions to create and print out lists:
    [list3] =>
    ** [list3]

    [3list] =>
    ** [3 list]

The second list is taken to have two elements, a number and a word.
The first has a single word "list3".

A numeric character can also be buried in the middle of a word which
starts with letters, e.g. "list3a".

Thus letters stick to each other, and to numbers 'on the right' or
'embedded'.

The word quote symbol """ can be used to tell POP-11 that you wish
to refer to a word, intead of using it as the name of something else
(i.e. as variable):








Sep 12 21:35 1984  chapter.2 Page 16


    "list3" =>
    ** list3

But if you give it an illegal combination of characters you will get
an error:

    "3list" =>
    ;;; MISHAP: IQW INCORRECT QUOTED WORD
    ;;; INVOLVING: 3

You can also make a word out of certain non-alpha-numeric
characters, i.e. sign characters:

    "*+*+*::\\^" =>
    ** *+*+*::\\^

But you cannot mix letters and sign characters:

    "+x" =>
    ;;; MISHAP ...

and in a list they will be separated into two:

    [+x] =>
    ** [+ x]

However, the underscore character can be used to join alphanumeric
type characters to sign characters, e.g. a list of one word:
    [+_x] =>
    ** [+_x]

The underscore can also be used as a convenient way of producing
long names which are readable. E.g. the following is the name of a
system variable:
    pop_readline_prompt

In general a sequence of characters made of "sign" characters and
letters will be broken at the point where the two sorts of
characters meet, unless they are joined by an underscore symbol "_",
e.g.
    fast_++         ++_lists_++

Two of the sign characters `/` and `*` play a special role in that
they can be combined to form the 'comment brackets', explained
aboved. So "/*" and "*/" cannot be used as words.

The separator characters cannot be used to join up with anything
else, except for the use of `.` in decimal numbers (e.g. 66.35).
This is because they play a special role in the syntax of POP11.
E.g. the following is a list of seven items
    [(.,)a"!] =>
    ** [( . , ) a " !]

The semicolon, though normally a separator which marks the end of an
imperative has a special role if repeated three times without
anything between: it marks an 'end of line' comment as explained







Sep 12 21:35 1984  chapter.2 Page 17


above. E.g.
    6 * 6 =>        ;;; this bit is ignored!
    ** 36

Some of the characters have special roles which will not be
explained fully till later. In particular '%' can be used in 'partial
application' and in 'unquoting' part of a list expression.

Strings, created using the string quote character can contain
arbitrary characters:
    'this is a *+*+*+* string %&$%$ of rubbish!!!'

except that if you wish to include the string quote itself in the
string it must be preceded by `\` to indicate that it doesn't mark
the end of the string. Here is a string containing the string quote:

    'isn\'t it' =>
    ** isn't it

Note that strings are normally printed without the outer quotes.

Characters themselves are represented by integers less than 128.
Since it is difficult to remember which number represents which
character (the so called 'ASCII code'), the character quote can be
used to tell POP-11 to read a character as representing the number.
Thus the letter `A` has the code 65 and the numerals start from 48:
    `A` =>
    ** 65

    `0` =>
    ** 48
    `5` =>
    ** 53

To complicate matters further, it is possible to tell POP-11 that
you wish to alter its rules, by using the procedure item_chartype.
This is especially useful when defining a new language in terms of
POP-11. Details will not be given in this introduction. The on-line
file REF ITEMISE gives more information.

-- Revision questions -----------------------------------------

1. What is a programming language?

2. What is declarative programming?

3. What are expressions?

4. What are imperatives?

5. What are the main components of POPLOG?

6. Give examples of some of the sorts of objects POP-11 expressions
    can refer to.

7. Give examples of some of the sorts of imperatives one can







Sep 12 21:35 1984  chapter.2 Page 18


    construct in POP-11 and explain what they do.

8. Give an example of a POP-11 procedure, and explain how it is used
    and what it does.

9. Define a procedure which takes in three numbers, adds up the
    first two, and then multiplies the result by the third. Your
    definition could start:

        define addmult(x, y, z) -> result;

10. What is the difference between defining a procedure and calling,
    or invoking it?

11. Explain with examples what it means to say that a procedure
    takes a certain number of arguments, and does or doesn't produce
    a result.

12. What is the difference between printing something out and
    producing a result?

13. What is the difference between '=>' and '==>' ?

14. What is a comment, and how are comments expressed in POP-11?

15. What will the following print:
        pr(99);spr(100);pr(101);spr(102);pr(103);

16. What are predicates and how are they used in conditions?

17. Which of the following words are legal in POP-11?
        "cat5"  "5cat" "**+**"  "*cat*"  "_5cat"  "*_cat"

-- Built in POP-11 data types ---------------------------------

We have seen that a programming language allows you to construct
expressions which denote objects, and we have seen some examples of
POP-11 expressions. Programming languages differ in the range of
types of objects they can refer to. Often there is a fixed set of
"data types" built in to the language, e.g. numbers, words and
lists.

Some languages, including POP-11, allow you to extend the set of
data types indefinitely. In POP-11 this requires using the procedure
CONSKEY, or the RECORDCLASS and VECTORCLASS declarations, which will
be explained in a later section.

For now we shall concentrate only on the built-in types, which
suffice for many purposes.

WORDS       e.g. "cat" "dog", "***", "a", "xxx_yyy", "(", "!+*+*+!"

STRINGS     e.g. 'a',  '21385d73::;+*)(&%',  'string with spaces'

Words, unlike strings, are stored in a dictionary, and may be used
in a program to refer to something else. I.e. they can be used as







Sep 12 21:35 1984  chapter.2 Page 19


variable names. Expressions denoting words have strict formation
rules sketched in a previous chapter, and cannot, for example,
contain spaces, as strings can. (However there are procedures which
can construct words with arbitrary combinations of characters, even
though they cannot be typed in directly.)

NUMBERS. There are two sorts of numbers:
    INTEGERS    66  -33  99999
    DECIMALS    66.0  -33.0  77.35  9999.532  -6666.0

    (Note for experts:
    Decimals may be single or double precision. The latter are called
    DDECIMALS. Normally only single precision numbers are used. By
    making the variable POPDPRECISION TRUE, you can make POP-11 use
    double precision decimal numbers. This will allow more accurate
    calculations, but may make them slower.)

Numbers may also be represented relative to a base. The base is
indicated by an integer followed by a colon, preceding the number
itself. Thus, binary numbers are represented with the prefix '2:'. So:
    2:100 is the same as 4
    2:1011 is the same as 11
    8:101 is the same as 65
    2:1.1 is the same as 1.5
    8:1.1 is the same as 1.125

Note that the prefix '10:' is redundant. 10:999 = 999

CHARACTERS e.g. `a` `B` `9` `(`
    are represented using the character quote symbol "`". In the
    computer they are represented as integers in the range 0 to 127.
    E.g. `A` is 65, `B` is 66, `a` is  97.
    The file HELP ASCII gives full details on character codes.
    NOTE: `a` is a character, whereas 'a' is a string.

BOOLEANS (or truth-values)
    There are only two of these TRUE and FALSE.

LISTS
    These may be used to form a single object composed of
    arbitrarily many objects of any type, including lists. Many
    examples of lists are given in this introduction. Lists are
    strictly speaking a 'derived' data-type in POP-11, in that
    they are constructed out of pairs.

PAIRS These are two-element structures used to build lists.

    E.g. the list [A B C] is represented by a pair whose first
    element is the word "A" and whose second element is a pair whose
    first element is the word "B" and whose third element is a pair
    whose first element is the word "C" and whose second element is
    the empty list []. The empty list is a special object, also
    called NIL. Most of the time users do not need to think about
    pairs. The facilities for building and manipulating lists,
    described later, are designed to hide such irrelevant details!








Sep 12 21:35 1984  chapter.2 Page 20


REFERENCES These are one element structures, used in some advanced
    programs. There is no special syntax for representing them. They
    are constructed using the procedure CONSREF. E.g. consref(3),
    consref("cat"), consref([a list in a reference])

VECTORS     e.g. {a b c} {cat mouse 3 4} {'a string' in a vector}
    These are very like lists, but stored more compactly in the computer.

ARRAYS
    These are N dimensional structures whose components are accessed
    by N numbers, where N can be 1 or more.  E.g. a two dimensional
    array might represent a picture, and its components could be
    accessed by giving two numbers representing distance along and
    distance up, e.g. picture(3,5).

PROCEDURES
    These are sets of instructions, which tell the computer to do
    something. Some are built in to the POP-11 system. Others are
    added by the user. Unlike some languages, POP-11 treats
    procedures as objects, just like numbers or words. E.g.
    procedures can be stored in lists, or assigned to variables.

CLOSURES
    A closure is a combination of a procedure and some data for it
    to operate on.

PROCESSES
    A process is a combination of procedure and data and a record of
    how far the procedure has got in its execution. The process can
    be suspended and resumed as required.

UNDEFS
    When a new variable is created, it is given a default value,
    which is a special object which may print out something like:
    <undef xx>. Meeting one of these in an error message is usually
    an indication that you have forgotten to "initialise" a variable
    with an appropriate value.

KEYS
    Each data type has associated with it an object known as a KEY,
    which is a structure containing information about all objects of
    that type, such as what they are called, how they are to be
    printed, how many elements they are made of.

PROPERTIES
    A property is a table of associations between objects. A
    property can function as a sort of memory of what is linked
    with what.

TERMIN
    Termin is a unique object used to indicate the end of a sequence
    of items, e.g. the end of a sequence of characters read from a
    file.

DEVICES
    These are records assocated with files, terminals and other







Sep 12 21:35 1984  chapter.2 Page 21


    means of communication between the POP-11 system and the rest of
    the world.

EXTERNALS
    These are procedures written in another language, e.g. FORTRAN
    or PASCAL and linked into the POP-11 system.

PROLOGVARS
    These are one element records used as variables for the Prolog
    subsystem of POPLOG. Various utility procedures are available
    for manipulating them.

PROLOGTERMS
    These are a special class of vectors which will be introduced
    to improve the efficiency of the implementation of Prolog.

Most beginners  will not need to know about most of these
data-types. For very many programs it suffices to know only about
procedures, words, numbers and lists. Booleans are used in
conditional instructions or in tests for termination of loops.
Strings are useful for formatted printing, and they are also used as
names of files. Arrays are useful for representing two dimensional
image data. This introduction will only be concerned with the most
commonly used data types.

There is a portion of the computer memory which is referred to as
'the stack'. This is used as a general 'communication area' by
POP-11. We shall often refer to it as if it were an object, though
strictly speaking it is not. It cannot be manipulated liked an
object. For example, objects can be put on the stack, but the stack
cannot be put on the stack. The next chapter elaborates.
#E































Aug 27 18:40 1984  chapter.3 Page 1


#E
CHAPTER.3

-- THE STACK ------------------------------------------------------

We have referred to the stack several times already. The stack is a
portion of the computer's memory used by POP-11 for communicating
information between parts of a program. Procedures in POP-11 get
their arguments from the stack, and leave their results on the
stack. An expression denotes an object by causing it to be placed on
the stack. The assignment arrow "->" takes an item off the stack.

A full understanding of POP-11 requires an understanding of the
stack. What follows is an introductory explanation.

-- Assignment and the stack ---------------------------------------

Assignment, expressed by "->", is an operation which removes
something from the stack, and stores it somewhere else.

E.g. put four things on the stack

    3, "cat", 99, "blue";

The assignment arrow can be used to remove the top of the stack and
store it as the value of x.

    -> x;

Now print out what is left on the stack.
    =>
    ** 3 cat 99

I.e. only three things left. What was the fourth is now the value of x:
    x=>
    ** blue

Besides storing things in variables, assignment can be used to store
something in a structure. E.g. we may create a list, then use
assignment to alter its third element:

    vars list;
    [a b c d e] -> list;
    list =>
    ** [a b c d e]
    "D" -> list(4);         ;;; alter the 4th element
    list =>
    ** [a b c D e]

More generally, "->" can be used to invoke the 'updater' of a
procedure. This will not be explained in this introduction. For
readers with access to POPLOG, try HELP UPDATER.

We have seen that "->" can also be used in the heading of a
procedure definition, to define "output locals". In this context
"->" does not cause anything to be assigned. This is explained more







Aug 27 18:40 1984  chapter.3 Page 2


fully in the section on defining procedures.

-- Non-destructive assignment "->>" -------------------------------

The normal assignment arrow REMOVES the top item of the stack. It is
sometimes convenient to assign the top element of the stack yet
leave it there. This is done with the arrow "->>". For instance this
can be used to assign the same thing to several different variables:

    0 ->> x ->> y -> z;

This puts 0 on the stack, then COPIES the top of the stack into x,
then COPIES the top into y the MOVES the top of the stack into z.

-- Procedures and the stack ---------------------------------------

Consider a statement in which the value of an arithmetic expression
is printed, for example:

    2 + 2 =>
    ** 4

This statement is processed in two stages; firstly the arithmetic
expression is evaluated and then secondly the result is printed. The
result of evaluating the arithmetic expression is left on the stack,
from where the print routine removes it.

As with a stack of plates, the last thing put on the stack is the
first one you get off. Because the stack can accomodate more than
one result, it is possible to write several expressions separated by
commas, each of which causes something to be put on the stack. For
example:

    2 + 3,  10 * 2,  5 - 3 =>

If this instructions is obeyed then three numbers are put on the
stack with 5 at the bottom, then 20 and finally 2 on the top. The
print arrow prints the ENTIRE stack, starting from the bottom, and
empties it, thus:

    ** 5 20 2

Note that the top element of the stack is printed last.
(NB Inside a procedure '=>' prints only the TOP element of a stack,
since a procedure may have been called in a context where other
procedures have put things on the stack temporarily for other
purposes.

-- Assignment as a two stage operation ----------------------------

The statement:

    2 + 2 -> x;

takes place in two stages, viz: '2 + 2;' then '-> x;'








Aug 27 18:40 1984  chapter.3 Page 3


First the expression is evaluated and the result, 4, is left on the
stack. Then the top element of the stack is removed and put into the
variable x.

We can write a series of statements which put things on the stack
followed by a series which remove than and put them in variables,
for example:

    2; 3; -> x; -> y;

These four statements do the following:

    (1) Put 2 on the stack
    (2) Put 3 on the stack
    (3) Remove the top element (ie 3) and put it in the variable x
    (4) Remove the top element (ie 2) and put it in the variable y

So, the following will swap the values of x and y.
    x; y; -> x; -> y;

Expressions may be separated by commas, and assginments need no
separators, so this can be abbreviated to:

    x, y -> x -> y;

Notice that '-> x' removes the top item from the stack, and assigns
it to x, whereas the reverse operation:
    x;

Just COPIES the value of x onto the stack, leaving x unchanged. We
can demonstrate this difference as follows.

    vars x;
    77, 88, 99;     ;;; put three things on the stack
    -> x;           ;;; take one off
    =>
    ** 77 88        ;;; two things left

    x; x; x; =>     ;;; copy value of x three times onto stack
    ** 99 99 99

-- The stack and arithmetic expressions -----------------------

The stack is used while evaluating arithmetic expressions so that a
statement such as:

    2 + 3 -> x;

actually takes place in four steps, thus:

    (1) Put 2 on the stack
    (2) Put 3 on the stack
    (3) Do the addition, that is remove the top two items on the stack
        (ie 2 and 3) and replace them by their sum (ie 5)
    (4) Remove the top item from the stack (ie 5) and put it in
        the variable X.







Aug 27 18:40 1984  chapter.3 Page 4



A more complicated example, such as:

    2 + 3 * 4 - 5 =>

takes place in EIGHT steps, which are left as an exercise for the
reader to describe, some of which are:

    (4) Do a multiplication
    (5) Do an addition
    (7) Do a subtraction
    (8) Print the contents of the stack


-- Exercise ---------------------------------------------------

Work out and write down what happens when the following imperative is
obeyed:

    (2 + 3) * 4 + 5 - 2 =>

-- Multiple assignments -------------------------------------------

All the following imperatives use the stack:

        (a) expression =>
        (b) expression;
        (c) expression -> variable;
        (d) -> variable;

we can replace 'expression' by a sequence of expressions separated
by commas and we can replace '-> variable' by a sequence of such
things, for example:

    1, 2, 3 -> z -> y -> x;

After this imperative has been executed z will have the value 3 and
x will have the value 1. More usefully, after executing:

    x, y -> x -> y;

the values of x and y will have been swapped.

Beware of writing programs which leave things lying around on the
stack for later use in a wanton fashion. In early versions of POP-2
this was often done for efficiency. However it can make programs
hard to understand, debug, or modify.

-- Some procedures which work on the stack --------------------

STACKLENGTH
can be used to find out how many things are on the stack. When
invoked it counts the number of items on the stack and then leaves
that number on the stack, for example:

    2 + 3, 9 - 5, stacklength() =>







Aug 27 18:40 1984  chapter.3 Page 5


    ** 5 4 2

Notice that in POP11 a procedure which takes no arguments is invoked
by writing its name followed by two parentheses.

-- Clearing items from the stack (erase) --------------------------

ERASE
removes one item from the stack, for example:

    2 + 3, 9 - 5, erase() =>
    ** 5

or
    5 + 5, 66, erase(), 8 * 8, 10 - 5, erase() =>
    ** 10 64

The assignment arrow followed by ";" or "," (or any other expression
terminator) has the same effect as "erase()". Thus:

    5 + 5, 66, -> , 8 * 8, 10 - 5, -> =>
    ** 10 64

Whether you use this or "erase" is a matter of taste. (However,
"erase" has to be used when a stack-clearing procedure is referred
to explicitly, e.g. assigned to another procedure as input.)

ERASENUM
takes an integer and removes that number of items from the stack.
E.g.

    1,2,3,4,5,6; erasenum(2) =>
    ** 1 2 3 4

Which is equivalent to: erasenum(1,2,3,4,5,6,2) =>

SETPOP
clears the stack. For example;

    2 + 3;
    setpop();
    stacklength() =>
    ** 0

Setpop does many others things besides clear the stack; it also
aborts any running program. Consequently, it prints a message
whenever it is called. An immediate call of setpop occurs whenever
you type CTRL-C (unless you have redefined the procedure INTERRUPT,
described later).

-- Procedures communicate via the stack -----------------------

POP11 procedures take their parameters, if any from the top of the
stack, and leave their results, if any, on the stack. Thus the
procedure SIN removes the top item from the stack, computes its
sine, and place this number on the stack. When we write:







Aug 27 18:40 1984  chapter.3 Page 6



    sin(45) =>
    ** 0.707107

Then three things happen:

    (1) 45 is put on the stack
    (2) SIN is called (invoked, applied, run...). SIN removes the
        top item (in this case, 45), computes its sine (in this case
        0.7071), and puts this on the stack
    (3) The print arrow, '=>' prints and empties the stack.

Had we wished to be obscure, we could have written, with exactly the
same effect:

    45;
    sin();
    =>

If there is nothing on the stack for a procedure like SIN then it
complains and we get a MISHAP message.

Whatever is currently on the top of the stack is used by the
procedure SIN. If this expression were executed with the stack
empty, a MISHAP message would be printed indicating that the stack
had underflowed, thus:

    sin() =>
    ;;; MISHAP - STE: STACK EMPTY (missing argument? missing result?)
    ;;; DOING    :  sin compile compile

Provided the number of parameters (arguments) put on the stack when
a procedure is called is the same number as taken by the procedure,
any numbers previously on the stack are unaffected by the
transaction.

Note the difference between writing

        sin

which loads the sin procedure itself onto the stack and

        sin()

which actually causes the sin procedure to be executed.

-- The DOT-notation for procedure calls ---------------------------

Readers familiar with the language FORTH, you may be interested that
POP-11 admits an alternative notation for procedure calls. Instead of:

    perim(3,5) =>

you can use

    3, 5 .perim =>







Aug 27 18:40 1984  chapter.3 Page 7



I.e. the "." can be used to invoke a procedure. Thus POP11 allows,
instead of 'sin(45)', '45.sin', which can be interpreted as put 45
on the stack and then run SIN. Similarly
    sin(sqrt(100))

can be expressed as
    100.sqrt.sin

    sin(sqrt(100)) =>
    ** 0.173648

    100.sqrt.sin =>
    ** 0.173648

The latter notation corresponds more closely to the actual order of
processing, though the former is the more conventional way of
representing procedure calls. We shall not use this POSTFIX notation
in this introduction, though it is popular with some POP-11 users.

-- Removing unwanted items from the stack -------------------------

The procedure erase simply removes one item from the stack, so in:

        erase(2 + 2) =>

the expression in the parentheses will be evaluated but no result
will be printed. Erase is sometimes useful if you want only one of
the results of a procedure which produces two results. E.g. the
operation '//' performs integer division putting the remainder and
the quotient on the stack:
        23 // 6 =>
        ** 5 3

If you wanted to assign only the remainder to X, you could do:
        erase(23 // 6) -> x;
        x =>
        ** 5

(Actually the infix operation REM does the same:
        23 rem 6 -> x;
        x =>
        ** 5
)

To assign the divisor first assign the top of the stack, then erase
the second result:

    erase(23 // 6 -> x);
    x =>
    ** 3

(This can be done instead using the infix operator 'div':
    23 div 6 =>
    ** 3
)







Aug 27 18:40 1984  chapter.3 Page 8



-- Swapping items using the stack ---------------------------------

As described earlier, the following swaps the values of X and Y:

    x, y -> x -> y;

The statement:

    -> x -> y; x, y;

has a rather different meaning. Effectively, it swaps the top two
elements of the stack and as a side-effect stores the top two items
in x and y.

If we wanted to swap the first (ie top) and third elements of the
stack we could do:

    -> x -> y -> z; x, y, z;

-- Conditionals and the stack -------------------------------------

Previously we noticed that the use of a conditional like

    if x = 10 then x=> endif

depended on the fact that "=" is a predicate, i.e. a procedure
producing a boolean result. This result is left on the stack. You
can think of a conditional imperative of the form

    if <condition> then <action> endif

as being roughly equivalent to something like the following:

    1. Put value of <condition> on stack

    2. If the top element of the stack is true perform the
        <action>, otherwise jump to after 'endif'.

This means that if the expression between 'if' and 'then' produces
no result, then an error will occur. For example, "3 = x" produces a
boolean result, whereas the assignment "3 -> x" is simply an
imperative, and does not, so:

    if 3 -> x then x => endif;

    ;;; MISHAP - STE: STACK EMPTY (missing argument? missing result?)

The portion of POP-11 between 'if' and 'then' produced no result.

Strictly speaking, POP-11 is defined so that anything other than
false can be used as equivalent to true in a condition:

    if 99 then 66 => endif;
    ** 66








Aug 27 18:40 1984  chapter.3 Page 9


For this reason it is sometimes convenient to define a procedure so
that it returns either false or some object it is discovered. For
example, a procedure which searches down a list looking for a word,
and if it finds it returns that word as its result, otherwise
returns false:

    define findword(list) -> result;
        vars item;
        for item in list do
            if isword(item) then
                item -> result;
                return();
            endif;
        endfor;
        false -> result;
    enddefine;

    findword([1 2 3 4 5 6]) =>
    ** <false>

    findword([1 2 3 4 five 6]) =>
    ** five

This might be used with the non-destructive assignment arrow thus:
    vars w;
    if findword(list) ->> w then
            .... do something with w ....
    else
            report_failure();
    endif;
#E
































Jul  7 15:02 1984  chapter.4 Page 1


CHAPTER.4

-- Arithmetic: basic facilities -------------------------------

As implied above, POP-11 has two sorts of numbers: integers and
decimals. The latter are often called 'reals', or floating point
numbers.

There are several procedures for manipulating numbers. Most of these
are 'infix' procedures. That is they can be used to create expressions
without using parentheses, e.g. 3 + 5, 77 * 9, although it is legal to
write +(3, 5) or *(77, 9) instead if you prefer.

The following operations are available for constructing arithmetic
expressions:

    +   add two numbers
    -   subtract two numbers, or negate one number.
    *   multiply two numbers
    **  exponentiation: e.g. A ** 3 means A*A*A i.e. A cubed.
    /   divide first number by second
    //  divide first number by second, produce
        remainder and quotient.

    >   test two numbers: TRUE if first greater than second.
    <   test two numbers: TRUE if first less than second.
    >=  test two numbers: TRUE if first greater than or
        equal to second.
    <=  test two numbers: TRUE if first less than or
        equal to second.

    X div Y returns the number of times Y goes into X. Both integers.
    X rem Y returns the remainder on dividing X by Y.
        (Instead of REM it is possible to use MOD).

Most of the above are 'binary' operations. That is, they require TWO
arguments. For example the expression
    3 + 4
applies the operation + to the two arguments 3 and 4. It denotes the
number 7. The arguments may themselves be complex expressions, e.g.
    (3 + 4) + (5 + 6)

The operation - can be binary (two arguments) or unary (one argument),
and POP-11 works out from the context which it is. When it is unary, as
in
    - 4
or
    - (3 + 5)

it produces a number by NEGATING its argument.

When it is a binary operator, as in
    3 - 4
or
    (2 + 1) - (2 + 2)








Jul  7 15:02 1984  chapter.4 Page 2


it subtracts the second argument from the first. So the latter denotes
the number -1.

What sort of thing is denoted depends on the operator.  E.g. consider:

    99 > (X + Y)

This takes the expression '99' and the expression '(X + Y)' each of
which may denote a number, and creates a new expression which denotes
true or false, depending on whether the first number is greater than or
less than the other. I.e. > is a binary operator, taking two numbers and
producing a TRUTH-VALUE, i.e. a BOOLEAN as a result. So
    99 > 66        denotes TRUE
    66 > 99        denotes FALSE

Here are some more expressions formed using arithmetic operators:
    (X + Y) * (99 - Z/3)

This has even more sub-expressions, e.g. X, Y, 99, Z, 3, X + Y, Z/3,
etc. You can print out the value of an expression by using the print
arrow "=>". The result is printed out preceded by '**'. E.g.
    3 + 5 * 2 =>
    ** 13

    (3 + 5) * 2 =>
    ** 16

Notice how parentheses can affect the order in which operations are
applied.

The operator // is unusual in that it produces two results. It takes two
integers, and produces two integers, a remainder and a divisor, as in:

    10 // 3 =>
    ** 1 3

    23 // 10 =>
    ** 3 2

-- Other arithmetic procedures --------------------------------

Other arithmetic procedures available in POP-11 include:
    ABS(x)      absolute value (modulus) of X
    EXP(x)      exponential of x (e to the power x)
    FRACOF(x)   fractional part of a decimal number
    INTOF(x)    integer part of a decimal number, positive or negative
    MAX(x,y)    the bigger of two numbers
    MIN(x,y)    the smaller of two numbers
    SIGN(x)     -1 if x is negative, + 1 if positive, 0 if x = 0, or 0.0
    RANDOM(x)   a random integer in range 1 to x
    ROUND(x)    the integer nearest to x
    ARCCOS(x)   trigonometric arc cosine of angle
    ARCTAN(x)   trigonometric arc tangent of angle
    COS(x)      trigonometric cosine of angle
    LOG(x)      natural logarithm of a number - inverse of EXP
    NEGATE(x)   negation of the number (i.e. -x)







Jul  7 15:02 1984  chapter.4 Page 3


    SIN(x)      trigonometric sine of angle
    SQRT(x)     square root of number
    TAN(x)      trigonometric tangent of angle


NOTES:
    The procedure NEGATE is useful when unary minus is required
    as an argument to or result of a procedure.
    The trigonometric procedures use degrees, unless the variable
    popradians is set TRUE. The default is FALSE (i.e. use degrees.)
    (This is one of a large collection of user definable global
    variables controlling the behaviour of POP-11.
    See HELP POPVARS).

All of these procedure names can be used to create expressions denoting
numbers. E.g.
    sqrt(9)  denotes the number 3.0

and max(4,77) denotes the number 77.

Arithmetic expressions can be embedded in others. For example
the expression
        tan(23 + 22)
is equivalent to
        tan(45)

which denotes the number  1.0 (if POPRADIANS is FALSE), and
    tan(45) + tan(45)
denotes the number 2.0, and finally
    max(min(66,33), min(999,9))

denotes the number  33, as does:

    max( min(66-5, 33), min(999, 9+9) ) =>
    ** 33

-- Using a radix other than 10 ------------------------------------

POP-11 will read in binary numbers if they are preceded by '2:'

    2:111 =>
    ** 7

Similarly octal numbers may be preceded by '8:'
    8:111 =>
    ** 73

This sort of prefix can be used for non-integer numbers too:

    8:11.11 =>
    ** 9.140625

The integer base must be in the range 2-36; if greater than 10, the
letters A-Z (uppercase only) can be used in the number to represent
digit values from 10 to 35, e.g. 16:1FFA represents 8186 as a
hexadecimal number.







Jul  7 15:02 1984  chapter.4 Page 4



How numbers are printed is controlled using pop_pr_radix, which
defaults to 10. By making it 16 numbers can be printed in
hexadecimal, for instance:
    16 -> pop_pr_radix;
    16 =>
    ** 10
    15 =>
    ** F

-- POP_PR_RADIX, POP_PR_PLACES and POP_PR_EXPONENT ----------------

The printing of decimal (floating point) numbers is also controlled
by pop_pr_radix.
    16 -> pop_pr_radix;
    15.55 =>
    ** F.8CCCCD

The number of decimal places shown is controlled by pop_pr_places,
which defaults to 6.
    10 -> pop_pr_radix;
    sqrt(2) =>
    ** 1.41421
    8 -> pop_pr_places;
    sqrt(2) =>
    ** 1.41

A value of 0 causes decimal numbers to be printed as integers.

If pop_pr_exponent is made true (it defaults to false) then exponent
form is used for printing:

    true -> pop_pr_exponent;
    sqrt(20000) =>
    ** 1.41421e+2

This notation can also be used for reading in decimals:
    false -> pop_pr_exponent;
    1.41421e+2 =>
    ** 141.421

-- Illustrating popradians ----------------------------------------

The variable popradians controls whether the trigonometric
procedures take arguments, or produce results in degrees or radians.
We can use the fact that "pi" is a built in constant thus:
    true -> popradians;
    sin(90) =>
    ** 0.893997
    sin(pi/2) =>
    ** 1.0
    arcsin(1) =>
    ** 1.5708
    false -> popradians;
    sin(90) =>
    ** 1.0







Jul  7 15:02 1984  chapter.4 Page 5


    sin(pi/2) =>
    ** 0.027412
    arcsin(1) =>
    ** 90.0

-- RANDOM ---------------------------------------------------------

Expressions using random denote relatively unpredictable things.

    random(10) =>
    ** 8
    random(10) =>
    ** 4
    random(10) =>
    ** 1

The random number generator draws from a range of whole numbers
determined by the size of the number offered in the brackets. I.e.
random (10) will always return a number lying between 1 to 10
(inclusive). random (100) between 1 to 100 inclusive and so on.

The behaviour is controlled by a variable called ranseed, whose value
changes each time random is used. To make random produce a repeatable
sequence of results do:
    1 -> ranseed;
    random(100)=>
    ** 25
    random(100)=>
    ** 54
    random(100)=>
    ** 4

    1 -> ranseed;       ;;; restart the sequence
    random(100)=>
    ** 25
    random(100)=>
    ** 54
    random(100)=>
    ** 4

-- Random decimal numbers -----------------------------------------

To produce random decimal numbers between 0 and 1 you can define the
following procedure, using the fact that 536870911 is the largest
integer which POP-11 can represent.

    define random_decimal() -> result;
        (random(536870911) - 1) / 536870910 -> result
    enddefine;

    repeat 5 times random_decimal() => endrepeat;

    ** 0.078072
    ** 0.132751
    ** 0.195248
    ** 0.261654







Jul  7 15:02 1984  chapter.4 Page 6


    ** 0.328064

1 has to be subtracted from the result of random because random
returns a result greater than or equal to 1. Without subtracting 1
we can never get a result of 0 from random_decimal.

-- Exercises --------------------------------------------------

1. What are the data types of each of the following?
    33
    33.0
    8:777
    "cat"
    'asdf;lkj876 *+*++ '
    [1 2 3 4]

2. What do the following expresions denote?
    33 + 3
    3 + 4 * 5
    (3 + 4) * 5
    6 - 3.0
    sign(random(20))

If you have access to a computer running POP-11 you can test your answers
using '=>'. E.g.
    6 - 3.0 =>

3. What is the effect of the variable POPRADIANS?

4. How can you make pop-11 print in hexadecimal form?

5. Define a procedure which produces a random number between
    -1 and 1

6. What variable can be given the value 1 to make pop print numbers
    in binary notation?


-- Precedence and parentheses ---------------------------------

There is a syntactic complication in POP-11, like most programming
languages, which we have so far illustrated without commenting on.
Some procedures are run by writing their names before the parentheses,
with inputs between parentheses as in the imperative 'member(x, list)'.

By contrast some procedures, such as the arithmetic procedures '+', '*',
'-', are invoked by writing the name between the inputs, as in
    3 * 5, 77 + 7

etc. These are known as 'infix' operators. They are names of
ordinary procedures, but have special syntactic properties to
simplify their use. If the same expression contains two such infix
operators there may be an ambiguity. For instance: how is 3 + 4 * 5
to be understood? One way is to use parentheses to indicate whether
the addition or the multiplication is to be done first:








Jul  7 15:02 1984  chapter.4 Page 7


    (3 + 4) * 5 =>
    ** 35

    3 + (4 * 5) =>
    ** 23

Parentheses are also the principal way that we get round POP-11's
requirement that everything be written 'linearly'. So the 'ordinary'
way of writing a division

        7.50 + 19.43
        ____________
            27

becomes

        (7.50 + 19.43)/27 =>
        **  0.99740741

Each of the infix operations of POP-11 has a 'precedence' associated
with it. A precedence is a number which determines the order in
which the operations are applied. Both '+' and '-' have a precedence
of 5. '*', '/', and '//' however have a precedence of 4, indicating
that these operations are applied before addition and subtraction
where brackets are not used to remove any ambiguity. Thus
    3 + 4 * 5 =>
    ** 23

Here the multiplication is done first because its precedence is lower
than that of '+'. In the case of operators of equal precedence they
are applied from left to right, thus, since "*" and "/" have equal
precedence:

    6 / 2 * 5 =>
    ** 15

not:
    6 / (2 * 5) =>
    ** 0.6

The precedence table for arithmetic operations is as shown below.

        Operation       Precedence
        div                2
        rem                2        (mod can be used instead)
        **                 3
        * / //             4
        + -                5
        > < >= <=          6
        =                  7

Using this table it can be seen that the result of typing the statement

    3 - 2.5  ** 2 * 1.5 / 3 =>

will be







Jul  7 15:02 1984  chapter.4 Page 8



    ** -0.125

The order of evaluation is as follows:

Original expression                     3 - 2.5 ** 2 * 1.5 / 3
Apply operations of precedence  3       3 - 6.25 * 1.5  /3
Apply operations of precedence  4       3 - 3.125
Apply operations of precedence  5       -0.125

The precedence associated with each operation defines an order of
evaluation of an expression. If another order is required, parentheses
can be used in the conventional way. For example:

    (3 - 2.5) ** 2 * 1.5 / 3 =>
    ** 0.125

The rules of precedence apply to each expression within a pair of
parentheses.

Parentheses may be nested to any depth, the expressions within inner
parentheses being evaluated first.

Where parentheses are not present, and the precedences do not uniquely
define an order of evaluation, then evaluation proceeds from left to
right. I.e. operations associate to the left. So
    3 / 4 / 5

is equivalent to
    (3 / 4) / 5
which denotes  0.15, unlike
    3 / (4 / 5)
which denotes  3.75.

NOTE for experts:
The HELP PRECEDENCE file gives more information on precedences in
POP-11. Precedences in POP-11 may be positive or negative numbers in the
range -12.7 to +12.7.

It is possible for an infix operation to have a negative precedence,
in which case it will associate to the right, altering the order of
execution.

The procedure called 'identprops' can be used to find out the
precedence of an operator. For an ordinary variable the precedence
is 0. For an infix operator it will be some other number. For a
syntax word or macro (see later) identprops produces the word
"syntax" or "macro". If applied to something which has not been
declared by the user or the system, it produces the result undef.
Thus:

    identprops("+") =>
    ** 5

    identprops(">") =>
    ** 6







Jul  7 15:02 1984  chapter.4 Page 9



    identprops("if") =>
    ** syntax

    identprops("help") =>
    ** macro

    vars x;
    identprops("x") =>
    ** 0

    identprops("xxx") =>
    ** undef

-- Defining new infix procedures ------------------------------

(Beginners should omit this section.)
Users may define their own new infix operators by specifying the
precedence after the word 'define'. E.g. to define an operation of
precedence -3.5 /// which divides its first argument by the square of
its second, and associates to the right:

    define -3.5 x /// y;
        x / (y * y)
    enddefine;

    3 /// 4 =>
    ** 0.1875
    4 /// 5 =>
    ** 0.16
    3 /// 4 /// 5 =>
    ** 117.187
    (3 /// 4) /// 5 =>
    ** 0.0075

Infix procedures are available for other purposes besides numerical
operations. We shall see later that "<>" is an infix operation which can
join two objects together, for instance, and "matches" is an infix
operation used for comparing two lists. The equality symbol "=" is also
used for an infix operation.

-- Testing for equality and inequality ------------------------

It is often necessary to use conditional imperatives, in order to
write flexible programs which do not always do the same thing. This
requires the ability to test certain conditions, to see if they are
true or false. An important class of such tests is testing for
equality or similarity.

    ==  test any two objects. TRUE if they are identical:
        i.e. not really two objects but one and the same.
        (Strict equality)

    =   test any two objects. TRUE if they are identical,
        OR if they are of the same type with the same elements,
        i.e. if they are 'similar'.







Jul  7 15:02 1984  chapter.4 Page 10



NOTE in most versions of POP apart from POP-11, the symbol "=" is
used for STRICT equality, and the procedure EQUAL is provided to
test for similarity. In this version "=" is equivalent to EQUAL.

E.g.

    3 == 3      is TRUE because it's the same thing, the number 3
                that's referred to on both sides.
    3 == 5 - 2  is also TRUE for the same reason.
    [A B C] == [A B C]  is FALSE, since they are two lists
                Each time POP-11 reads in '[ .... ]' it creates a
                new list, even if there was a similar one earlier.
    [A B C] = [A B C]  is TRUE, since they are two SIMILAR lists.
    'A STRING' == 'A STRING'    is FALSE, because there are two strings
but
    'A STRING' = 'A STRING'     is TRUE, because the two strings are
                                similar

Thus it is possible to have two lists or strings with the same
components, but which are not the very same object, e.g. if you type
in the string 'silly' twice.
    'silly' == 'silly' =>
    ** <false>

If you type in the same number twice POP-11 will not treat the two
expressions as denoting two different objects. So 999 will always
refer to the same number. Strings and lists are different.

Words have to be treated like numbers. POP-11 has to know about
certain words, e.g. "define", "if", "(" and to be able to recognize
new occurrences of the very same word. So words are entered in a
dictionary when they are first read in, and if an expression
denoting a word with the same characters is read in later, then
instead of creating a new object POP-11 finds the same word in its
dictionary and re-uses that.

Thus, words, unlike strings, are 'standardised' in a dictionary, so
that you cannot have two different words with the same characters. If
you attempt to type in a second one, POP-11 will find the original in
its dictionary, and assume you wanted to refer to it. So both the
following are TRUE:

    "CAT" == "CAT" and  "CAT" = "CAT"

Writing two expressions on either side of an equality operation
produces a new expression, which denotes a truth-value, TRUE or
FALSE. In other words = and == each take two arguments and produce
one BOOLEAN result.

-- Numerical comparisons --------------------------------------

Besides = and ==, there are other operations provided for comparing
numbers, e.g.
        <         >       <=      >=








Jul  7 15:02 1984  chapter.4 Page 11


Each of these takes two numbers and produces a boolean result:

    99 > (33 + 55) =>
    ** <true>
    99 > 99 =>        ;;; is 99 greater than 99
    ** <false>
    99 >= 99 =>     ;;; is 99 greater than or equal to 99
    ** <true>
    (33 * 3) < (66 * 2) =>
    ** <true>
    99 < 99 =>
    ** <false>
    99 <= 99 =>        ;;; is 99 less than or equal to 99
    ** <true>

More complex facilities are required for comparing complex structures
when you are not looking for an exact match, but want to recognise cases
of partial similarity. For example, a conversational program may wish to
detect lists of words starting with [ who is ....] and treat them
differently from lists of words starting with [where is...]. We
shall see later how the 'matches' operation can be used to achieve
this.









































Sep 12 21:40 1984  chapter.5 Page 1


CHAPTER.5

-- Defining procedures ----------------------------------------

We have already seen some examples of procedure definitions. Here is
a specification of the format for a procedure definition:

    DEFINE
        then <name of procedure>
        then <formal parameters in parentheses, separated by commas>
        then -> <output local> (if required)
        then semi-colon
        then action to be performed
            (may include conditionals, loops, etc.)
        then ENDDEFINE;

Example - a procedure, named DOUBLESUM which takes two numbers, and produces
a new number got by doubling the sum of the two.

    define doublesum (num1, num2);
        2 * (num1 + num2)
    enddefine;

This definition produces a result, even though it does not use an output
local. This because the procedure calls first '+' (add) then '*'
(multiply), and the latter leaves its result on the stack. So since
DOUBLESUM does not remove the result of '*', it is left as the result of
DOUBLESUM also.

We can make it clearer to ourselves, and readers of our programs if we
indicate that a procedure is to produce a result, by using an 'output
local' variable in the procedure heading, as we did previously, thus:

    define doublesum (num1, num2) -> result;
        2 * (num1 + num2)   -> result
    enddefine;

(NOTE for experts: though clearer this is marginally less efficient,
since it has an extra local variable, and does an extra assignment and
stack operation.)

Another example - if you already have a graphics package which
includes a procedure called draw, which takes a number and draws a
line, and aprocedure called  turn, which takes a number in degrees
representing the angle to turn, then you can define a procedure
named SQUARE which will take a number, and will draw a square of the
appropriate size:

    define square (side);
        repeat 4 times
            draw(side); turn(90);
        endrepeat;
    enddefine;

This procedure produces no result. So there is no need for an output
local.







Sep 12 21:40 1984  chapter.5 Page 2



-- Executing (calling, running, applying) a procedure -------------

An imperative telling POP-11 to run, or invoke, a procedure, is formed
by writing the procedure name, followed by parentheses, with any
arguments (if any are needed) between the parentheses. E.g.

    square(5);

I.e.: execute the procedure square with 5 as argument. i.e. the input
variable, or formal parameter, SIDE gets the value 5.

    doublesum(3,99) =>
    ** 204

I.e.: execute the procedure doublesum, with 3 and 99 as arguments. I.e NUM1
gets the value 3 and NUM2 the value 99. The result is printed out by =>

    doublesum(4,60) -> x;
      i.e. as before, but assign the result to X.

-- Procedures with more than one output local -----------------

If a procedure is to return one or more results, it can be given
OUTPUT LOCALS. We have already seen examples of procedures with one
output local variable, e.g. doublesum, above, and several others
before that. Sometimes it is convenient to have a procedure produce
more than one result.

For example, here is a procedure which takes a list of numbers and produces
the sum of all the numbers, and their average, i.e. two results. The two
results are left on the stack when the procedure exits.

    define stats(numlist) -> sum -> average;
        vars item;
        0 -> sum;
        for item in numlist do
            item + sum -> sum;
        endfor;
        sum/length(numlist) -> average
    enddefine;

    vars s a;
    stats([ 1 3 5 9 ]) -> s -> a;
    s =>
    ** 18
    a =>
    ** 4.5

NB output locals are like ordinary local variables in that the values
assigned to them during execution of the procedure are not available
after the procedure has finished. E.g. if you try to access the values:

    sum =>
    ** <undef sum>
    average =>







Sep 12 21:40 1984  chapter.5 Page 3


    ** <undef average>

Output locals can be assigned to anywhere in the procedure. When the
procedure finishes, the values of the output locals are left on the
stack. In the example above the values are then taken off the stack
after the procedure STATS has finished, and assigned to A and to S.

So the order in which they are put on the stack is the REVERSE of
the order in which they occur in the procedure heading. The order of
the assignments to take them off the stack is the same as the order
in the procedure heading. Thus the procedure heading gives the
FORMAT for a typical call of the procedure in which the results are
assigned.

-- Different types of procedures ------------------------------
   (This section may be omitted by beginners)

Procedures come in four types: normal, infix, macros and syntax.
(Strictly speaking, it is variables that come in four types - their
values are in all cases simple procedure records).

A normal procedure is one which is invoked by writing its name,
followed by an opening parenthesis, its arguments (if any) separated
by commas and finally a closing parenthesis, for example:

    foo(x + 1, y)

This applies the procedure in the variable FOO to the results of
evaluating the expressions 'X + 1' and 'Y'.

An infix procedure is invoked by writing its names between its
arguments. (Typically, infix procedures have two arguments). For
example '+' is an infix procedure, thus:

    3 + 4

Infix procedures have a numerical precedence to disambiguate
expressions such as:

    3 + 4 * 5

In such expressions, infix procedures with the LOWEST numerical
precdence are evaluated first. The precedence of '*' is 4 and that
of '+' is 5 so the above expression is equivalent to '3 + (4 * 5)'.
Otherwise infix procedures with a positive precedence are evaluated
left to right. Thus if +++ were defined as an infix procedure of
precedence 3, then

    a +++ b +++ c +++ d

would be equivalent to

    (((a +++ b) +++ c) +++ d)

However, if the precedence is negative, the operation will associate
to the right. So if +++ had precedence -3, then







Sep 12 21:40 1984  chapter.5 Page 4


    a +++ b +++ c +++ d

would be equivalent to:
    (a +++ (b +++ (c +++ d)))

For more on precedence see HELP DEFINE and HELP PRECEDENCE.

Macro procedures are evaluated at compile time (ie when read in by
the compiler). Their arguments (if they have any) are bound to the
individual following text items, not the following expressions: so
if the macro SWAP has two arguments
then the expression

    'SWAP X Y' is correct
but
    'SWAP HD(X) HD(Y)' is wrong

(since SWAP would get HD and '(' as its arguments). (For more on macro
definitions, see HELP MACROS.)

Syntax procedures do not take arguments. They too are executed at
compile time. System syntax words, such as IF, DEFINE, UNTIL correspond
to syntax procedures: they typically read in some or all of a POP-11
expression and tell the compiler how to understand it.

More detailed information is provided in the online files: HELP SYNTAX
and REF SYNTAX.

We now give examples of some of the more commonly used forms of syntax.


-- Loops: instructions to do something repeatedly -------------

Several looping constructs are provided.

For compatibility with older systems, wherever the word DO is used in
the examples below, the word THEN is also accepted. Similarly most
looping constructs will accept CLOSE or ENDDO as the closing bracket,
for consistency with POP-2 and earlier versions of POP-11.

-- UNTIL <condition> DO <action> ENDUNTIL ------------------------

This means, check if the <condition> is true, and if not then do the
action. Then test again to see if the condition is true. And so on.
The condition is tested again each time AFTER <action> is done. For
example, to print out all the numbers from 3 to
99 do:

    vars num;
    3 -> num;
    until num > 99
    do    num =>
      num + 1 -> num;
    enduntil;

The <action> element of a loop (like a conditional) may be an







Sep 12 21:40 1984  chapter.5 Page 5


arbitrarily complex pop-11 imperative, or sequence of imperatives.
So to print out the words "THE" "CAT" "SAT" "ON" "THE" "MAT", you
could make a list of the words, then keep printing out elements of
the list. We use the system procedure TL which, when given a list,
returns a new list containing all except the first element of the
original. chop one off. until the list is [], thus:

    vars list;
    [the cat sat on the mat ]  -> list;
    until list = []
    do
        list(1) =>                  ;;; print first element
        tl(list) -> list;           ;;; prepare for next
    enduntil;

NB the loop will not be terminated immediately if the condition
becomes TRUE in the middle of executing the action. Note also that
the condition is always tested at least once BEFORE anything else is
done.


-- REPEAT <number> TIMES <action> ENDREPEAT -----------------------

After the word REPEAT you can have a number, e.g. 4, or a variable whose
value is a number, e.g. REPEAT N TIMES...
or a more complex expression which calculates a number,
      e.g. REPEAT 66 + 53 TIMES....

The <action> will be done the specified number of times.

Example: to print out  10 blank lines, do

    repeat 10 times pr(newline) endrepeat;

See also the definition of procedure SQUARE, above.

For indefinite iteration do

    REPEAT <action> ENDREPEAT;

e.g.

    repeat
        [you are wonderful] =>
    endrepeat;

You will need to interrupt (e.g. with CTRL-C).


(See HELP LOOPS for more on interrupting loops)

-- WHILE <condition> DO <action>  ENDWHILE -----------------------

This means, test the condition. If it is true, then do the action. Then
test the condition again. And so on. This is similar to UNTIL, except
that WHILE does the action each time the condition is found to be TRUE







Sep 12 21:40 1984  chapter.5 Page 6


whereas UNTIL does the action each time the condition is found to be
FALSE. In both cases the condition is tested first.

E.g. to find the first integer whose square is greater than 1000, you
could do:

    vars num;
    1 -> num;
    while num * num < 1000 do
        num + 1 -> num
    endwhile;

The value of num and its square can now be printed out:
    num =>
    ** 32
    num * num =>
    ** 1024

-- 'FOR ... ENDFOR' loops -----------------------------------------

We have seen examples of the use of the 'for ... endfor' construction,
to iterate over lists. In fact there are several different formats.

This is the most general:

   FOR <initiate> STEP <step> TILL <condition> DO
      <action>
   ENDFOR;

This is equivalent to:

      <initiate>;
      UNTIL <condition> DO <action>; <step> ENDUNTIL;

In other words, do the initialisation, then, until the condition evaluates to
TRUE, repeatedly do the action followed by the step.

For example, to print out all the numbers from LO to HI, separated by spaces:

    for   lo-> x
    step  x+1 -> x
    till  x > hi
    do    spr(x);
    endfor;

N.B. The 'step' is not done until after the 'action'.

Suppose FOO is a procedure of two arguments, a word and a number.
If you are given a list of words and a list of numbers and wish to
apply FOO to the first element of each, then the second element of each,
etc., until either there are no more words, or no more numbers, you
could do something like:

    vars w, n;
    for   words -> w; numbers -> n;
    step  tl(w) -> w; tl(n) -> n;







Sep 12 21:40 1984  chapter.5 Page 7


    till  w = [] or n = []
    do    foo(hd(w), hd(n));
    endfor;

________________________________________________________________

    FOR X IN LIST DO <action> ENDFOR;

X will take on as its value the first element of LIST, then the second
element, then the third, etc. Each time the <action> is performed the
latest value of X will be used. E.g. printing out the squares of a list
of numbers

    for num in numbers do
        pr('\nThe square of: '); pr(num); pr(' is: '); pr(num*num);
    endfor;

(Note: this uses strings. '\n' in a string causes a new line to be
printed.)

  ________________________________________________________________

    FOR L ON LIST DO <action> ENDFOR;

Here, the first time the <action> is done L will refer to the whole LIST.
The second time it will refer to the TAIL of the list (i.e. a list of all but
the first element). The next time a still shorter list, and so on.
E.g.

    for l on [a b c] do l=> endfor;
    ** [a b c]
    ** [b c]
    ** [c]

  ________________________________________________________________

    FOR X FROM <number> BY <number> TO <number> DO
      <action>
    ENDFOR;

e.g. to print out numbers from 2 to 20 going up in steps of 7

    for x from 2 by 7 to 20 do  x => endfor;
    ** 2
    ** 9
    ** 16

or going down:
    for x from 50 by -12.5 to -20 do x => endfor;
    ** 50
    ** 37.5
    ** 25.0
    ** 12.5
    ** 0.0
    ** -12.5








Sep 12 21:40 1984  chapter.5 Page 8


the 'FROM <number>' and 'BY <number>' portions can be omitted. The
starting value defaults to one, as does the increment.

    vars x;
    for x to 6 do pr(x); pr(space) endfor;
    1 2 3 4 5 6

-- Conditionals. These can have several forms -----------------

All the <conditions> in what follows should be expressions which
evaluate to TRUE or FALSE.

(1) IF <condition> THEN <action> ENDIF;

(2) IF <condition> THEN <action1> ELSE <action2> ENDIF;
     if the <condition> is true, then <action1> will be executed,
     otherwise <action2> will be executed.

(3) IF <condition1> THEN <action1>
    ELSEIF <condition2> THEN <action2>
    ELSEIF <condition3> THEN <action3>
    ELSEUNLESS <condition4> THEN <action4>
    .............
    .............
    ELSE <default action>
    ENDIF;

This 'multi-branch' conditional says:

    try <condition1> then <condition2> etc in turn until an ELSEIF
    condition is found which is TRUE, or an ELSEUNLESS condition is
    found which is FALSE. If either is found, execute the
    corresponding <action>.  If none of the conditions comes out
    TRUE then do the thing following ELSE, i.e. <default action>.

Note that in an imperative you don't have to have the ELSE <default
action> bit. You must, however, have it in an expression intended to
denote, something, for then it should denote something under all
conditions. You can include as many ELSEIF clauses as you like.


  (4)   UNLESS <condition> THEN  <action> ENDUNLESS;
       this is equivalent to:
       IF NOT(<condition>) THEN <action> ENDIF;

UNLESS can also have ELSEUNLESS and ELSEIF and ELSE clauses.

Note: the words NOT, AND and OR are available for use in formulating complex
conditions. E.g.

    IF <condition1> OR (<condition2> AND NOT(<condition3>))

-- Examples ---------------------------------------------------

To test whether the value of X is bigger than the value of Y, and
print out the bigger value do:







Sep 12 21:40 1984  chapter.5 Page 9



    if    x > y
    then  x =>
    else  y =>
    endif;

Compare:

    if       x > y
    then     x =>
    elseif   y > x
    then     y =>
    else     "same" =>
    endif;

    if    2 < x and x < 6
    then  true
    else  false
    endif =>

Note that the last example is exactly equivalent to:

    2 < x and x < 6  =>

If LIST1 and LIST2 are two lists and you want to print out the one
which is shorter you could do:


    if    length(list1) < length(list2)
    then  list1
    else  list2
    endif =>

If N and M are two numbers, and you wish to assign the bigger
one to the variable MAX then do:


    if    m > n
    then  m
    else  n
    endif -> max;

-- Switch statements ------------------------------------------

POP11 provides a command GO_ON which can be used thus

  GO_ON <numerical expression> TO <label1> <label2> <label3> ...<labeln>;

The expression must evaluate to a number in the range 1 to N, if N
is the number of labels. The labels must be repeated elsewhere in
the procedure, followed by colons. For instance, the following will
translate numerals:

    define trans(num);
      go_on num to la lb lc ld;
      la: "one" ; return;







Sep 12 21:40 1984  chapter.5 Page 10


      lb: "two" ; return;
      lc: "three" ; return;
      ld: "toobig";
    enddefine;
    trans(2) =>
    ** two

A GO_ON instruction may end with ELSE <default label> ;
See HELP GO_ON.

-- Tracing ----------------------------------------------------

To trace some procedures, type TRACE, followed by the names of the
procedures. example:

    trace square doublesum;

will cause the two procedures to be traced whenever they are
executed. UNTRACE is used to undo tracing, e.g.

    untrace square doublesum;

-- More on POP11 constructs -----------------------------------

A POP11 program is a piece of text, which may be composed of
combinations of:

* Declarations  (e.g. variable declarations, procedure definitions).

* Imperatives   (e.g. assignments ( X + Y -> X), procedure calls).

* Expressions   (e.g. 3, 99 + X, HD(LIST), HD(TL(LIST)))

Roughly, declarations say how something is to be used, but don't ask
the computer to do anything yet; while imperatives say do something
which will produce a change of some kind in the machine or on the
terminal; and an expression is a sort of name for an entity which is
to be computed in a manner specified by the expression. So the
declaration

    vars fred, x, y;

says that FRED, X and Y are to be used as names of variables. The
imperative

    add([fido isa dog]);

tells POP11 to put a new list into the DATABASE, whereas the expression

    hd([fido isa dog])

is a name, or referring expression, denoting the first element of
the list, namely the word "FIDO". A typical place where you'd use an
expression is on the left hand side of an assignment, e.g.

    hd([fido isa dog]) -> w;







Sep 12 21:40 1984  chapter.5 Page 11



or in a sequence of expressions representing the input to a
procedure, e.g.

    last(database) matches hd(patternlist)

which has two expressions denoting inputs to the procedure MATCHES.
The whole thing can be used to denote the result of MATCHES, i.e.
TRUE or FALSE, and is therefore also an expression.

Imperatives and declarations are separated by semi-colons ';' (or
the print-arrow '=>' or '==>', whereas expressions (e.g. inputs to a
procedure) are separated by commas ','. An imperative does not need
a semi colon immediately before a closing bracket, such as ')',
'ENDDEFINE', 'ENDIF'. (Some people would call declarations a type of
imperative.)

Sometimes you cannot tell from its form whether something is an
expression or an imperative. That depends on context. Thus, a
conditional (see below) may be an imperative, as in:

    if x > y then x -> max else y -> max endif;

which specifies which of two things to DO, whereas in

    if x > y then x else y endif -> max;

the whole thing is an imperative, whereas the bit between IF and
ENDIF is an expression which denotes either the value or X or the
value of Y, depending on which is greater. The conditional
expression (the bit between IF and ENDIF) says which of two things
is to be DENOTED, rather than which of two things is to be DONE.

Looping constructs (e.g. using UNTIL, WHILE, FOR, REPEAT, FOREACH,
FOREVERY, - see below) are normally imperatives but can also
sometimes be used as expressions, like conditionals.

There are several kinds of 'primitive' expressions in POP11, e.g.

* Identifiers   (X, MATCH, LIST, etc - used as names of something else)

* Quoted words ("X", "MATCH", "LIST" - used to refer to themselves)
    Identifiers and quoted words are entered in a dictionary to
    prevent the same one being created twice.

* Strings of characters ('X', 'A LONGER STRING', '19827364&!#&%$$')
    These are partly like words, but are not in the dictionary,
    so two different strings may have the same characters.

* Numbers (integers: 3, 999, reals: 3.1415926, 3.0,
        binary numbers: 2:10111001
        octal numbers:  8:77315)

An important type of expression in POP11 which is not primitive is a
LIST expression, which may contain expressions of other sorts, e.g.








Sep 12 21:40 1984  chapter.5 Page 12


    [ a list of five words ]
    [two words [a list] 'a string' 99 %x + y%]

Another type, used when it is important to save space, is the VECTOR,
which is a one-dimensional array of objects, e.g.

    {a vector with five words and 99 [a list] 'a string'}

Notice that 'curly' brackets are used for vectors, square brackets
for lists. More information on vectors can be found below.

This is not a complete list of types of expressions. In fact, by
defining new macros or syntax words, the user can extend the set of
expression formats used.

-- Vectors (Sometimes called 'strips') ------------------------

A vector is a data structure made of some number of elements, stored
consecutively in the memory of the computer, unlike lists, which are
chains of items, where links in the chain may be located in very
different places. Lists are more flexible in that new links can be
inserted into a list, but they also occupy more space in the
computer. A list of N elements takes up 3N machine words (e.g.
12Nbytes on a VAX), whereas a vector of N elements takes up N+2
words.

To create a vector you can use the brackets { .... } e.g.

    {3 cat [a list] 99 }

is a vector containing two numbers, a word and a list. The vector
brackets, like list brackets, 'quote' their contents. I.e. names of
variables are not replaced by their values, and if there is a piece
of enclosed POP-11 program it is not executed, as in {99 + 9}, which
is a vector containing two numbers and a word, not just one number.
In vector expressions, as in list expressions, the percent symbol
can be used to cause POP-11 expressions to be evaluated. So, if you
need a vector to contain the values of some variables, or the result
of some computation, use {% .... %} e.g.

    {% "cat", hd(list), x+y, list %}

Warning, although in many ways vectors are like lists, HD and TL
cannot be applied to them.

NOTE for experts:
"^", "^^" and MATCHES (defined below) can be used with VECTORS as well
as with LISTS. However "?" and "??" do not work for vectors with
MATCHES.

To access an element of a vector, use a numerical index. E.G.

    {a cat} -> x;
    x(2) =>
    ** cat








Sep 12 21:40 1984  chapter.5 Page 13


For efficiency and clarity the procedure SUBSCRV is also available.
It takes a number and a vector and returns (or updates) the
corresponding element of the vector.
    subscrv(2,x) =>
    ** cat

    "mouse" -> subscrv(1,x);
    x =>
    ** {mouse cat}

The first element of x has been altered, by the 'updater' of
SUBSCRV. Altering structures in a program can sometimes lead to
confusing programs and is frowned on by purists. But it is often
very useful for instance in recording a changing situation.

Vectors can be concatenated, like lists words, strings, and other
entities, using <> .
    {a word} <> { and some more words} =>
    ** {a word and some more words}

For more details see REF VECTORS. Users can define their own classes of
vectors. See HELP VECTORCLASS.

-- Strings (Character vectors) --------------------------------

A string is a special kind of vector containing character codes,
stored compactly.

String constants may be typed in between string quote marks, e.g.

    'A string with letters and spaces' -> string;

If the string is to extend over several lines, then a backslash
character, "\" must appear at the end of each line of the string,
e.g.:

    'This is the first line\
    and this is the second' -> string;

Assigning true to pop_longstrings makes it possible to leave out the
backslash.

Alternatively, you can insert a newline character into the string
thus:

    'This is the first line \nand this is the second' -> string;

I.e. "\n" inserts a newline. Similarly "\'" inserts a string quote, "\b",
inserts a back-space character, "\t" inserts a tab, "\s" inserts a
space, and "\r" inserts the 'carriage retern character (code 13).

Strings can be concatenated using the infix operation ><, e.g.

    string1 >< string2  -> string3;

will assign to STRING3 a string formed by joining the strings







Sep 12 21:40 1984  chapter.5 Page 14


referred to by STRING1 and STRING2. The arguments of >< don't have
to be strings. They can also be words or numbers, but the result
will always be a string. So, if the value of X is an integer, to
create a string made of the corresponding characters, concatenate it
with the empty string thus:

    x >< ''  -> numstring;

Normally strings are printed out without their quote marks.

The elements of a string are integers representing character codes.
They can be accessed by numerical indexing, e.g.

    'cat' -> x;
    x(2) =>
    ** 97

(assuming it's a lower case 'a').

The procedure SUBSCRS, which takes a number and a string, is
available for more efficient accessing and updating of string
elements.

See HELP STRINGS for more details.







































Sep 12 23:54 1984  chapter.6 Page 1


CHAPTER.6


-- Recursion --------------------------------------------------

We have previously seen how new procedures can be defined in terms of
old ones. Using display_room we defined display_data. Using the
procedures pr, perim, area, volume, we defined display_room. Using
arithmetic operations we defined the procedures perim, area, volume.

We can use procedures we have already defined to create yet more
procedures, to form a 'procedural hierarchy'. For example, if we
want to know the perimeter of a square, then its length and its
breadth are the same. So we can use the previously defined PERIM
procedure to define SQUARE_PERIM.

    define perim(len, breadth) -> result;
        (len + breadth) * 2 -> result
    enddefine;

    define square_perim(side) -> result;
        perim(side, side) -> result
    enddefine;

Then we can ask SQUARE_PERIM to do its stuff, and it will in turn
ask PERIM to do its stuff.

    square_perim(3) =>
    ** 12


Procedures can not only make use of the definition of other
procedures. They can also make use of their own definition. This
concept is very powerful but can be puzzling. It will not be
explained here but only illustrated.

For some kinds of statistical and algebraic calculations we need to
add up (or multiply) a sequence of numbers starting from 1 going up
to some target number. In 'desk-calculator mode' POP11 can handle
that:

        1 + 2 + 3 + 4 + 5 + 6 =>
        ** 21
        1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 =>
        ** 45

What is the underlying pattern here?

-- An infinitely recursive procedure ------------------------------

Thinking of 6 as the 'target number' the first sequence could be
described as:
     (sum of numbers up to one less than the target) + TARGET

That is








Sep 12 23:54 1984  chapter.6 Page 2


    define sumup(target) -> result;
        sumup(target - 1) + target -> result
    enddefine;

This is almost right but it fails to handle SUMUP(1) which we intend
to be 1 but will actually come out as SUMUP(0) + 1 but SUMUP(0) is
SUMUP(-1) + 0! This is an infinite regression.

If you try to use it you will have to interrupt with CTRL-C (or
whatever the interrupt character is on your system):

    sumup(5) =>

If you don't interrupt you'll get a mishap message eventually:

    ;;; MISHAP - RLE: RECURSION LEVEL EXCEEDED
    ;;; DOING    :  sumup sumup sumup sumup sumup sumup sumup sumup sumup
         sumup sumup sumup sumup sumup sumup sumup sumup sumup sumup sumup
         sumup sumup sumup sumup sumup sumup sumup sumup sumup sumup sumup
         sumup sumup sumup sumup sumup sumup sumup sumup sumup sumup sumup
         sumup sumup sumup sumup sumup sumup sumup sumup sumup sumup sumup

The mishap message, will be very long, and you'll need to use CTRL-C to
interrupt that!

(Typing HELP RLE or EXPLAIN RLE will get you more information about
what's going on.)

-- Stopping the recursion -----------------------------------------

The possibility of such infinite regressions often worry people when
they first encounter the idea of recursion. We need a STOPPING
CONDITION in this case to ensure that SUMUP(1) is 1. To encode that
we shall need to use a conditional statement:

    define sumup(target) -> result;
        if target = 1 then
            1 -> result
        else
            sumup(target - 1) + target -> result
        endif
    enddefine;

We can now test this as follows:
    sumup(1) =>
    ** 1
    sumup(2) =>
    ** 3
    sumup(5) =>
    ** 15

-- Making things clearer with TRACE ---------------------------

We said that SQUARE_PERIM caused PERIM to run. This can be seen if
we use TRACE, which alters procedures so that they print out
information whenever they are invoked and whenever they finish. E.g.







Sep 12 23:54 1984  chapter.6 Page 3



    trace perim, square_perim;

This does not print anything out, but it does alter the procedures
PERIM and SQUARE_PERIM.

Now test perim on its own:
    perim(3, 5) =>
    >perim 3 5                  ;;; starting
    <perim 16                   ;;; finishing
    ** 16

and square_perim:

    square_perim(5) =>
    >square_perim 5             ;;; starting square_perim with 5
    !>perim 5 5                 ;;; starting perim with 5 and 5
    !<perim 20                  ;;; perim finishes with result 20
    <square_perim 20            ;;; so does square_perim
    ** 20

Here
    !>perim 5 5

means entering perim, while already in a traced procedure. '>' means
entering. '!' means while in a traced procedure. If it were inside
two traced procedures, we'd get '!!'. This will be shown in the next
example.

The behaviour of SUMUP defined to call itself may not have been at
all obvious to you. You can see more clearly what is going on if you
change the procedure sumup, using TRACE, thus

        trace sumup;

That does not cause sumup to be executed (if it did you get a mishap
because there isn't an argument on the stack for it). It alters the
procedure so that IN FUTURE it will behave differently. E.g.
        sumup(1) =>
        >sumup 1            ;;; going into sumup with argument 1
        <sumup 1            ;;; coming out with result 1
        ** 1

        sumup(2) =>
        >sumup 2
        !>sumup 1
        !<sumup 1
        <sumup 3
        ** 3

        sumup(5) =>
        >sumup 5
        !>sumup 4
        !!>sumup 3
        !!!>sumup 2
        !!!!>sumup 1







Sep 12 23:54 1984  chapter.6 Page 4


        !!!!<sumup 1
        !!!<sumup 3
        !!<sumup 6
        !<sumup 10
        <sumup 15
        ** 15

Study this carefully remembering that '>' means entering, '<' means
leaving, and the vertical marks indicate how many traced procedure
calls are active at the time.

You can selectively switch off tracing using UNTRACE;

    untrace perim;
    square_perim(5) =>
    >square_perim 5
    <square_perim 20
    ** 20

Note only PERIM is no longer traced. Similarly

    untrace sumup;

    sumup(10) =>
    ** 55

-- Recursing on a tree --------------------------------------------

The rest of this chapter may be found difficult on first reading.
It may become clearer for beginners after reading the next chapter,
on list processing.

The arithmetica example was chosen for is relative simplicity.
Recursion is not restricted to arithmetical processes. It is widely
use in non-numerical work on language and thinking and also in the
programming of perception. A common non-numerical application of
recursion is searching a tree or network - e.g. searching a family
tree.

A simple example is searching through nested lists for a list
starting with a given word. E.g. here is a list of lists.
    vars facts;
    [ [tom age 20 wife [mary age 30] ]
      [suzy age 60 husband
            [joe nationality british father
                    [fred age 93 wife [sally age 94]]
            ]
        ]
    ] -> facts;

If you want to search such a list to find if it contains a list
starting with "joe" you can look at the first element, and see if it
is "joe". If not, and it is a list, then search that list. If you
have still not found the word after that, then search the remainder,
the 'tail' of the original list. We can express this more clearly in
POP-11 as follows. We use the two procedures HD (i.e. 'head') and TL







Sep 12 23:54 1984  chapter.6 Page 5


(i.e. 'tail'). HD, when applied to a list, produces the first element
of the list as its result. TL, when applied to a list, produces a
list of the remaining elemens. We also need the procedure, ATOM, to
recognise something which is not a list at all, eg. a word.

-- Defining SEARCH_FOR --------------------------------------------

    define search_for(target,list_of_lists) -> result;
        if atom(list_of_lists) then
            false -> result;    ;;; can't find target in an atom.
        elseif hd(list_of_lists) = target then
            list_of_lists -> result
        else
            search_for(target, hd(list_of_lists) ) -> result;
            unless result then
                search_for(target, tl(list_of_lists)) -> result

            endunless;
        endif;
    enddefine;

Notice the recursive call of search_for, first on the head of
list_of_lists, then on the tail, if the first call produces a FALSE
result. We can try this out to see if there is a list starting with
"joe" in the facts list, given above.

    search_for("fred", facts) ==>
    ** [fred age 93 wife [sally age 94]]
    search_for("sally", facts) ==>
    ** [sally age 94]
    search_for("tom", facts) ==>
    ** [tom age 20 wife [mary age 30]]

whereas searching for something not there:
    search_for("margaret", facts) ==>
    ** <false>


We can, as before, use tracing to reveal what happens in the
recursive activations;
    trace search_for;
    search_for("joe", facts) ==>
>search_for joe [[tom age 20 wife [mary age 30]] [suzy age 60 husband [joe
         nationality british father [fred age 93 wife [sally age 94]]]]]
        ;;; this shows the search starting with the whole facts list
        ;;; not yet the target, so continue on head of list
!>search_for joe [tom age 20 wife [mary age 30]]
!!>search_for joe tom
!!<search_for <false>
        ;;; no good, so keep going down the tail
!!>search_for joe [age 20 wife [mary age 30]]
!!!>search_for joe age
!!!<search_for <false>
!!!>search_for joe [20 wife [mary age 30]]
!!!!>search_for joe 20
!!!!<search_for <false>







Sep 12 23:54 1984  chapter.6 Page 6


!!!!>search_for joe [wife [mary age 30]]
!!!!!>search_for joe wife
!!!!!<search_for <false>
!!!!!>search_for joe [[mary age 30]]
!!!!!!>search_for joe [mary age 30]
!!!!!!!>search_for joe mary
!!!!!!!<search_for <false>
!!!!!!!>search_for joe [age 30]
!!!!!!!!>search_for joe age
!!!!!!!!<search_for <false>
!!!!!!!!>search_for joe [30]
!!!!!!!!!>search_for joe 30
!!!!!!!!!<search_for <false>
!!!!!!!!!>search_for joe []     ;;; The empty list is an ATOM
!!!!!!!!!<search_for <false>
!!!!!!!!<search_for <false>
!!!!!!!<search_for <false>
!!!!!!<search_for <false>
!!!!!!>search_for joe []
!!!!!!<search_for <false>
!!!!!<search_for <false>
!!!!<search_for <false>
!!!<search_for <false>
!!<search_for <false>
!<search_for <false>
        ;;; that completes the unsuccessful search down the
        ;;; HEAD of facts. Now try the tail
!>search_for joe [[suzy age 60 husband [joe nationality british father
         [fred age 93 wife [sally age 94]]]]]
!!>search_for joe [suzy age 60 husband [joe nationality british father
         [fred age 93 wife [sally age 94]]]]
!!!>search_for joe suzy
!!!<search_for <false>
!!!>search_for joe [age 60 husband [joe nationality british father [fred
         age 93 wife [sally age 94]]]]
!!!!>search_for joe age
!!!!<search_for <false>

    ;;; and so on, until ....

!!!!!!>search_for joe [[joe nationality british father [fred age 93 wife
         [sally age 94]]]]
!!!!!!!>search_for joe [joe nationality british father [fred age 93 wife
         [sally age 94]]]
    ;;; and this succeeds, producing the prize list
!!!!!!!<search_for [joe nationality british father [fred age 93 wife [sally
         age 94]]]
    ;;; the result of the recursive call is assigned to the output
    ;;; variable 'result' in the line:
            search_for(target, tl(list_of_lists)) -> result
    ;;; so the same result is used for the earlier call, and so on:
!!!!!!<search_for [joe nationality british father [fred age 93 wife [sally
         age 94]]]
!!!!!<search_for [joe nationality british father [fred age 93 wife [sally
         age 94]]]
!!!!<search_for [joe nationality british father [fred age 93 wife [sally







Sep 12 23:54 1984  chapter.6 Page 7


         age 94]]]
!!!<search_for [joe nationality british father [fred age 93 wife [sally
         age 94]]]
!!<search_for [joe nationality british father [fred age 93 wife [sally
         age 94]]]
!<search_for [joe nationality british father [fred age 93 wife [sally age
         94]]]
<search_for [joe nationality british father [fred age 93 wife [sally age
         94]]]

    ;;; and the final result gets printed out
** [joe nationality british father [fred age 93 wife [sally age 94]]]


All these are comparatively simple examples of recursive procedures.
It is possible to have a large family of procedures which call one
another recursively, but this will not be illustrated here.
-- Recursion and local variables ----------------------------------

An important thing to remember is that all input and output
variables, e.g. target, list_of_lists and result, or any other
variables declared within the procedure using "vars" or "lvars",
will be LOCAL to the procedure. This means for each activation those
variables may have different values, and they will not interfere
with each other.






































Sep 13 00:00 1984  chapter.7 Page 1


CHAPTER.7

-- Lists: an introduction -------------------------------------

For work in Artificial Intelligence, and many other applications
where data needs to be represented in a variety of forms, lists are
a very useful data type. Lists can be used to represent or store
many kinds of information. They can contain any type of object,
including, for instance, numbers, words, procedures, and other
lists.

Note for experts: in fact LISTS in POP-11 are built out of a data
type called PAIRS, which are two-element records. A list is actually
a chained collection of pairs. But most of the time the user does
not need to know about this. High level facilities for manipulating
lists are provided, which conceal from the user the details of how
they are represented in the machine.

We have already met some expressions denoting lists. This section
will introduce some of the procedures used for manipulating lists.

REV, when given a list, produces a new version which has the same
elements in reverse order:

    rev([1 2 3 4]) =>
    ** [4 3 2 1]

LAST finds the final element of a list:
    last([cat dog mouse]) =>
    ** mouse

    last([[tom brown] [mary green] [suzy white]]) =>
    ** [suzy white]

Note that in this last example, the procedure LAST was applied to a
list of lists, and produced as its result a list, i.e. the last
list.

The first element of a list is often referred to as its HEAD, and in
POP-11 we call this the HD (whereas LISP uses CAR):

    hd([1 2 3 4]) =>
    ** 1

    hd(rev([cat dog mouse])) =>
    ** mouse

Check that you understand that. "[cat dog mouse]" is an expression
denoting a list. "rev([cat dog mouse])" is another expression
denoting a different list containing the same elements in reverse
order. Writing "hd(.....)" around that produces an expression
denoting the first element of that list.

Compare:

    hd(last([[tom brown] [mary green] [suzy white]])) =>







Sep 13 00:00 1984  chapter.7 Page 2


    ** suzy

The procedure 'tl' (read as 'tail') can also be given a list as
input. It will produce as its result a new list, containing all but
the first element of the original list.

    tl([a b c d e]) =>
    ** [b c d e]

Note that the tail of a two element list is a list containing the
second element. It is not the second element itself:

    tl([a b]) =>
    ** [b]

Compare:
    hd(tl([a b])) =>
    ** b

Note: 'hd' and 'tl' in POP-11 correspond to 'CAR' and 'CDR' in LISP.
'hd' and 'tl' are in fact defined in terms of yet more basic
procedures called 'front' and 'back', which are best not used by
beginners.

-- Exercise ---------------------------------------------------

What would the following denote:

    last(hd([[tom brown] [mary green] [suzy white]])) =>

    last(last([[tom brown] [mary green] [suzy white]]))

    hd(hd([[tom brown] [mary green] [suzy white]]))

    hd(tl([[tom brown] [mary green] [suzy white]]))

    tl(hd([[tom brown] [mary green] [suzy white]]))

    tl(tl([[tom brown] [mary green] [suzy white]]))


-- ONEOF and DELETE -------------------------------------------

A sometimes useful procedure for operating on lists is ONEOF which
selects neither the first nor the last, but chooses an element at
random. Thus using it on different occasions to do apparently the
same thing may or may not produce different results:

    oneof([eeny meeny miney moe]) =>
    ** meeny

    oneof([eeny meeny miney moe]) =>
    ** moe

    oneof([eeny meeny miney moe]) =>
    ** moe







Sep 13 00:00 1984  chapter.7 Page 3



When applied to a list of lists, it will produce a whole list as its
result:

    oneof([[a list] [another list] [a third list]]) =>
    ** [another list]

You can use ONEOF with the REPEAT form to flatter yourself thus:

    repeat 5 times
        oneof([ [you are gorgeous]
                [everyone loves you]
                [you are terribly brainy]
                [how masterful you are]
                [you are quite stunning]
            ]) =>
    endrepeat;
    ** [everyone loves you]
    ** [you are terribly brainy]
    ** [everyone loves you]
    ** [everyone loves you]
    ** [how masterful you are]

Note for experts:
Since ONEOF is defined in terms of RANDOM, illustrated previously,
the behaviour of ONEOF can be controlled by assigning to the
variable RANSEED, as in the case of RANDOM.

DELETE is a procedure which can produce copies of a list which do not
contain a certain element. Thus - to delete the number 3 from a list:

    delete(3, [1 2 3 4]) =>
    ** [1 2 4]

to delete a word from a list:

    delete("three", [I saw three ships]) =>
    ** [I saw ships]

The quote marks are necessary, outside of list expressions, to stop
a word like "three" being interpreted as a variable with a value.

Delete takes two arguments, the first which can be any item, while
the second must be a list. It produces one result, a list. The
resulting list will be empty, if the second argument contains only
occurrences of the first argument, thus:

    delete(3, [3 3 3]) =>
    ** []

To make DELETE stop before deleting all the found items, give it an
extra argument, saying how many to delete.
    delete(3, [3 3 3], 1) =>
    ** [3 3]

    delete(3, [3 3 3], 2) =>







Sep 13 00:00 1984  chapter.7 Page 4


    ** [3]

Using DELETE and ONEOF you can define a procedure to deal cards
from a pack:

    define deal(pack,num);
        vars card;
        repeat num times
            oneof(pack) -> card;        ;;; select a card
            delete(card,pack) -> pack;  ;;; remove it from the pack
            card =>                     ;;; print it out
        endrepeat;
    enddefine;

This procedure takes two arguments, a list and a number. It does
some printing, but does not produce a result. That is to say, the
things printed out are not left on the stack. 'card' is used as a
'local variable', which temporarily stores the selected card. Notice
that the line

            delete(card,pack) -> pack;

Alters the value of the variable 'pack' so that it refers to a list
no longer containing the card. The next time round the loop the card
will not be selected. Although that line removes the card from the
list, it is still the value of the variable 'card', so that it can
be printed out in the next line.
            card =>

We can test this with a pack of 12 cards, from which we want 6
dealt. We use S1 for ace of spaces, H2 for two of hearts, etc.

    deal( [ s1 s2 s3 h1 h2 h3 d1 d2 d3 c1 c2 c3 ] , 6);
    ** s1
    ** d2
    ** s2
    ** s3
    ** h1
    ** h3

No clubs this time.

-- More exercises on lists ------------------------------------

    1. Write down some examples of expressions denoting:
        a list of numbers
        a list of words
        a list of numbers and words
        a list of lists of words
        a list of lists of numbers

    2. What is denoted by each of the following:

        hd( [ once upon a time ] )
        last( [ mary had a little lamb ] )
        hd( [ [mary had] [a little lamb] ] )







Sep 13 00:00 1984  chapter.7 Page 5


        rev( [ mary had a little lamb ] )
        last( hd( [ [ mary had ] [ a little lamb ] ] ) )
        delete( "cat", [mouse pig cat dog] )


    3. What does oneof do?
        NB. Your answer should take the form:
        ONEOF is a procedure which takes one argument (or one input
        item) and produces one result. The argument must be a ....
        The result will be .....

    4. What does delete do?
        (I.e. how many arguments does it take? What sorts of things
        can they be? How many results does it produce? How is the
        result related to the arguments?)

    5. What do the following denote:

        delete(3, rev([ 1 2 3 4 5]) )

        rev( delete( "little", [mary had a little lamb] ) )










































Sep 13 00:04 1984  chapter.8 Page 1


CHAPTER.8

-- More list processing ---------------------------------------

This chapter provides more general information on syntax for
constructing lists, together with an overview of the basic
procedures available for operating on lists. A later chapter
revisits the matcher, giving more detail and showing how it is used
in the database procedures for operating on lists of lists.

A central thesis of much work in Artificial Intelligence is that
computation provides a good - perhaps the best - way to represent
the processes we call thinking, seeing, reasoning, speaking,
learning. But what sorts of computations? Not the manipulation of
numbers found in much scientific and engineering computation.
Intelligence rather seems to involve the manipulation of many kinds
of symbols which can be used to store information about many kinds
of things and their properties and relationships.

Many AI researchers have found that lists form a very general and
useful basic structure for storing such information. Lists, as we
have already seen can contain words, numbers, strings, and even
lists. Moreover, we can create lists of lists of lists of lists...
indefinitely. Thus there is no limit to the degree of complexity of
the information they can be used to represent. For instance, the
POP-11 database is defined as a list of lists, and operations on the
database are simply defined as operations on lists.

For now, we shall merely introduce some of the basic operations
which can be performed on lists. Later we illustrate their use in
connection with the database.

There are several things you need to know about lists:
    how to construct them, using "::", "<>" or "[...]"
    how to test them to see if they satisfy certain conditions
    how to extract information from them

-- Constructing lists -----------------------------------------

The simplest way to construct a list is to use square brackets. But
there are several others:

-- The use of [     ] ---------------------------------------

These "list constant brackets" may contain text items, i.e  words,
numbers strings, lists, or anything else. E.g.:

       [ A B C D]            is a list of four words
       [1 cat 2 dog 3 pig ]  is a list of six items.
       [string 'a short string' 66]
          is a list with a word a string and a number.

[]  is the empty list. Can also be called NIL.

List brackets may also be used to construct lists which contain lists,
E.g.:







Sep 13 00:04 1984  chapter.8 Page 2



       [ [1 2]  [3] 4 ] is a list with two lists and one number.

It contains exactly three elements, of which the first contains two.

-- The use of "%" in list expressions -------------------------

These "decorated list brackets" are used to create lists whose
contents depend on the values of variables or the results of
executing procedures. For instance:

       [ % 3, cat,  hd(l) % ]

is a list containing the number 3, the value of the variable CAT and
the first element of L, which must be a list, whereas

       [ 3, cat, hd(l) ]

contains the number 3, the comma, the word "CAT", a comma, the word
"HD", the word "(", etc.

        [% [% a %], [% b, c%], [% d %] %]

is a list of three lists, whose contents depend on the values of a b
c and d.

In earlier versions of POP-2 the symbol "%" could only occur at the
beginning or end of a list, i.e. next to the square brackets.
However in POP-11 this has been generalised to make it easy to mix
words and other text which is to be taken literally in the list with
bits of program to be executed. E.g.

    [the sum of 666 and 777 is % 666 + 777 % exactly] =>
    ** [the sum of 666 and 777 is 1443 exactly]

The symbols "^" and "^^" can be used for similar purposes.

-- The use of ^ (the "up-arrow" or "hat" symbol) --------------

"^(....)" can be used in place of "%....%". For example

    [the sum of 666 and 777 is ^(666 + 777) exactly] =>
    ** [the sum of 666 and 777 is 1443 exactly]

The parentheses after "^" can be omitted if they contain only one
item:

       [ ^X + ^Y is ^(X + Y) ]         is the same as
       [% X, "+", Y, "is", X + Y %]    and
       [ %X% + %Y% is %X + Y% ]

When followed by a variable, "^" means: "use the value of this
variable". When followed by a parenthesised expression, it means:

   "use the value of the parenthesised expression".








Sep 13 00:04 1984  chapter.8 Page 3


-- The use of  ^^  (double "up-arrow" symbol) ---------

This is used to merge the contents of a list into an enclosing list.
Thus:

       vars list;
       [ b c d ] -> list;
       [a ^list e ] =>
       ** [a [b c d] e]

       [a ^^list e ] =>
       ** [a b c d e]

The single "^" followed by a variable is used to insert a single
element in the list - the value of the variable, even if it is a
list. By contrast "^^" followed by a variable whose value is a list
inserts the elements of the list separately. The prefix "^^" can be
thought of as "remove the list brackets".

If the value is not a list, an error will result.

    vars x;
    99 -> x;
    [a b c ^^x] =>

    ;;; MISHAP - LIST NEEDED
    ;;; INVOLVING:  99
    ;;; DOING    :  compile


-- The operation :: -------------------------------------------

This is an operation for joining an element onto an existing list,
to make a new list, e.g.

       3 :: [4 5 6]     is  a list of four numbers.
       "CAT" :: []      is  the same as [CAT]
       "CAT" :: "DOG"   will cause an error,

since :: must have a list as its second argument. Notice that

       x :: y

is equivalent to

       [^x ^^y]

The former happens to be slightly more efficient.

-- The procedure CONSPAIR -------------------------------------

This is a procedure, which can be thought of as equivalent to :: .
That is

        conspair(x,l) is the same as  x :: l








Sep 13 00:04 1984  chapter.8 Page 4


The only difference is that the second argument of CONSPAIR need not
be a list. E.g.

       conspair(3, 4) -> l;
       l =>
       ** [3|4]

NOTE the use of the vertical bar - indicating that the number 4 is
not the second element of the list, as in [3 4]. Rather this is not
a list at all, since a non-empty list must have as its 'tail', or
'back' another list, possibly the empty list. l now has 4 as its
back, and 4 is not a list. Attempting to treat it as a list, e.g.

       tl(l) =>

This now produces an error, because TL insists on a proper list, and
a pair whose second element is not a pair is not acceptable. The
procedure BACK has no such qualms.

       back(l) =>
       ** 4

CONSPAIR is rarely needed in straightforward programs. Experts
sometimes use it, along with FRONT and BACK, instead of HD and TL,
for efficiency, as they do less checking. (FAST_FRONT and FAST_BACK
do even less checking, and can be used by experts in fully debugged
programs, at their own risk!) POP-11 includes mechanisms for
creating and using 'dynamic lists', whose elements are created as
needed by a generator procedure. This is sometimes referred to as
lazy evaluation. Only HD and TL can be used to access the first and
remainder of a dynamic list. (See HELP PDTOLIST for details.)

-- The concatenator  <> ---------------------------------------

This is an operator which takes two lists and "concatenates" them to
produce a new list. The first list is copied, so that the original
does not have any extra elements added to its end. E.g.

       [cat dog ] <> [pig mouse]  is the same as
       [cat dog pig mouse]

       lista <> listb

means: make a new list containing the elements of LISTA and the
elements of LISTB.

       [^x] <> l -> l    is the same in effect as
       x :: l -> l;
or
       [^x ^^l] -> l;

But the former is much less efficient, since <> copies the first
list. Notice that when X and Y are lists:

       x <> y








Sep 13 00:04 1984  chapter.8 Page 5


   is equivalent to

       [^^x ^^y]

The former has no advantages except that it is slightly more
efficient.

The operator <> can also be used to join two words, two vectors, two
strings or even two procedures. E.g.

    "cat" <> "catcher" = "catcatcher" =>
    ** <true>

    {one two } <> {three four} =>
    ** {one two three four}

To illustrate using <> to join two procedures we take the procedure
sqrt, which takes a number and produces its square root, and pr
which prints something, and combine them.

    sqrt(4);            ;;; prints nothing - result left on stack
    pr();               ;;; now print it
    2.0

    vars prsqrt;
    sqrt <> pr -> prsqrt;       ;;; concatenate two procedures
    prsqrt(4);                  ;;; now finds square root and prints.
    2.0

-- Using lists ------------------------------------------------

We now give some simple examples illustrating the information
given above.

There are many tasks where we will need to choose an element from a
pool of items e.g. from a deck of 'Court' cards like King of Hearts,
Jack of Diamonds etc. We have already met 'oneof' which chooses at
random.

    oneof([kh jd qc qh as]) =>
    ** kh
    oneof([kh jd qc qh as]) =>
    ** qc

The nice thing here is that lists are very flexible, they aren't
designed to hold an item of a fixed size or type.

More important still is the way that lists can be used to represent
mental STRUCTURES, for example the structure of a sentence.

       [[the boy] kicked [the ball]]
       [[the dish] [ran away] [with [the spoon] ]]

This idea of a list structure flows from the fact that an element of
a list can itself be a list. These brief remarks do not do justice
to the topic, they are intended only as motivation for what is







Sep 13 00:04 1984  chapter.8 Page 6


inevitably rather a formal presentation. You may like to read
Raphael, THE THINKING COMPUTER, Ch2

-- Basic operations on lists ----------------------------------

(a) Specifying the contents of a list - [] and % %.

      vars box;
      [shoes tins brushes] -> box;

declares a variable BOX and gives it a value which is a list
containing three items.

      vars cupboard;
      [box blanket pillow] -> cupboard;

Will similarly construct a list of three items.

      cupboard =>
      ** [box blanket pillow]

How does POP-11 know that the 'BOX' referred to here is not the
variable we declared earlier but the literal word "BOX"? The answer
is - 'By convention'.

The square brackets are used where the items listed are to be
understood literally and not read as names of other things (e.g.
other lists) or as procedures that will yield something we want put
into the list. I.e. inside the square brackets words are QUOTED. If
we wanted that mention of 'BOX' to denote the list that BOX contains
then we must indicate that it is the value of BOX rather than its
literal form that  is to be used.

       [%box% blanket pillow] -> cupboard;
       cupboard =>
       ** [[shoes tins brushes] blanket pillow]

The percent signs signal 'value of' to POP-11. Of course we could
construct this list without the percents:

       [[shoes tins brushes] blanket pillow]-> cupboard;

Compare:
       vars x y; 3 -> x; 4 -> y;
       [the sum of x and y is x+y] =>
       ** [the sum of x and y is x+y]

Here POP-11 has not evaluated X,Y but simply quoted them. But if we
use percents appropriately:

       [the sum of %x% and %y% is %x+y%]=>
       ** [the sum of 3 and 4 is 7]

POP-11 has evaluated X, Y and the arithmetic expression X+Y, and it
is the results of the evaluations that appear in the list.








Sep 13 00:04 1984  chapter.8 Page 7


As an alternative to using the pair of percent symbols to bracket a
variable or expression to be evaluated, the '^' (up-arrow) can be
used alone as a prefix. Thus we can rewrite that last example:

       [the sum of ^x and ^y is ^(x+y)] =>
       ** [the sum of 3 and 4 is 7]

On some terminals the up-arrow looks like a little upside-down 'V'.
On others the keyboard uses an arrow pointing up. Notice that if the
uparrow is to precede a complex expression, the expression must be
surrounded by parentheses. Parentheses are not needed when the
uparrow precedes a variable.

(b) Joining lists together - <>

Lists-within-lists is an important feature but we'll also need to
join lists end-to-end. We have already met the concatenator.

       [box] <> [cupboard] =>
       ** [box cupboard]
       [a b] <> [c d e] <> [f] =>
       ** [a b c d e f]

If we want the two lists that are in BOX and CUPBOARD joined
together then we need to use the variable names 'unprotected' as it
were by the '[' and ']' brackets that turn those names into quoted
words:

       box <> cupboard =>
       ** [shoes tins brushes [shoes tins brushes] blanket pillow]

Note that the original lists are unchanged by this:

       box =>
       ** [shoes tins brushes]
       cupboard =>
       ** [[shoes tins brushes] blanket pillow]

The operator <> creates a new list, by copying. Strictly, it is
redundant, since you can always get the same effect by using list
brackets and the "^^" prefix. E.g.

    box <> cupboard             IS THE SAME AS  [^^box ^^cupboard]
    [^^box ^^(tl(cupboard))]    IS THE SAME AS  box <> tl(cupboard)


(c) Accessing list elements - HD, TL

The items in a list can be accessed one at a time, using the
procedure 'HD' (pronounced 'Head'). The HD of a list is its first
element, thus

       hd(box) =>
       ** shoes

Note that SHOES is not itself a list. It is a word. We can also store







Sep 13 00:04 1984  chapter.8 Page 8


numbers in lists

   hd([351 two 79 rubbish]) =>
   ** 351

The first element may be a LIST as for example

   hd(cupboard)=>
   ** [shoes tins brushes]

And the HD of that list is "SHOES".

Getting access to anything other than this first element requires us
to combine together successive applications of HD or of HD and the
other basic procedure TL (Pronounced 'Tail'). Thus:

   hd(hd(cupboard)) =>
   ** shoes

POP-11 tackles this in several stages working from THE INSIDE OUT.

    1) ...(...(CUPBOARD))
        gets the value of CUPBOARD, which is the list:
            [[SHOES TINS BRUSHES]] BLANKET PILLOW]

    2) ...(HD(...))
        Then do the first (innermost) HD to it.
        The first element of the list above is:
            [SHOES TINS BRUSHES]
        which is now available for:

    3) HD(...(...))
        Then do the final (outer) HD operation to select its
        first element, which is the the word:
            SHOES

An alternative to using HD is to pretend that the list variable e.g.
CUPBOARD is a PROCEDURE and apply it to the number 1 to get the
first element. E.g.

   cupboard(1) =>
   ** [shoes tins brushes]

Similarly to get the second and subsequent elements

   cupboard(2) =>
   ** blanket
   cupboard(3) =>
   ** pillow

But CUPBOARD(4) will produce a mishap message.

To get the second element of the first element of CUPBOARD do:

   cupboard(1)(2) =>
   ** tins







Sep 13 00:04 1984  chapter.8 Page 9



The procedure TL (TaiL) is the list minus its first element (i.e.
NOT just the second element.):

   tl(cupboard)=>
   ** [blanket pillow]
   hd(tl(cupboard)) =>
   ** blanket
   hd(tl(tl(cupboard)))=>
   ** pillow

Notice that TL always returns a LIST (unless you apply it to an
empty list). Thus

   tl(box)=>
   ** [tins brushes]
   tl([onething])=>
   ** []

What do you think the following will do? ([] is an empty list.)

   tl([]) =>

^
    ;;; MISHAP - NON-EMPTY LIST NEEDED
    ;;; INVOLVING:  []
    ;;; DOING    :  tl compile

Notice the lack of symmetry between HD and TL. HD(BOX) is the same
as BOX(1). But TL(BOX) is not the same as BOX(2): it is a list of
remaining elements, or [] if there aren't any more.

Moving around lists using HD and TL can be clumsy and laborious,
though the consistency and simplicity of these two primitive
operations is an attractive feature. We shall see later that we have
much more global ways of accessing list contents - the MATCHES
procedure. Underneath these more powerful modes of list processing
there are however the basic operations of HD and TL.

-- Exercises --------------------------------------------------

Here are some puzzles to test your understanding. If we assign [a b] to
x, thus:

    [a b] -> x;

then the list [^^x c] is [a b c] and the list [^x c] is [[a b] c].

What values would have to be assigned to x, y etc so that the
following were true (some are impossible - which ones?):

    [^^x ^^x] = [a b a b]         ;;; answer is [A B] -> X;
    [^x ^^y] = [[a b] b c]        ;;; answer is [A B] -> X; [B C] -> Y;
    [^^x mother ^^y] = [i love my mother]
    [the height of steve is ^^x] = [the height of steve is 70 inches]
    [every ^^x is a ^^y] = [every fire man is a civil servant]







Sep 13 00:04 1984  chapter.8 Page 10


    [every ^x is a ^y] = [every fire man is a civil servant]
    [^^x i ^^y you] = [sometimes i hate people like you]
    [[^x ^^y] ^^z] = [[a b c d]]
    [^x [^^y] ^z] = [[a b] [c d] [e f]]
    [i saw ^^n ships] = [i saw 3 ships]
    [i saw ^n ships] = [i saw 3 ships]
    [i ^x you] = [i hate computers]
    [^x ^y ^z] = [i hate computers]

Use the computer to check your answers. For example, if you think
the answer to the fourth one is:

    [6 feet] -> x;

then try printing the list:

    [the height of steve is ^^x] =>

Later you will see that the procedure MATCHES could be used to find
the answers.

-- Procedures and lists ---------------------------------------

Getting to the bottom of a list by nested calls of TL as in
HD(TL(TL(CUPBOARD))) looks very clumsy. What would a procedure look
like which traverses a list printing out each element as it
progresses?

   define traverse(list);
     if  list = [] then
         'finished' =>
     else
         hd(list) =>
         traverse(tl(list))
     endif;
   enddefine;

   traverse(box);
   ** shoes
   ** tins
   ** brushes
   ** finished

You may find it a little easier to understand the following version,
which is strictly equivalent. ("/=" means "is not equal to")

   define traverse(list);
     if  list /= [] then
         hd(list) =>
         traverse(tl(list))
     else
         'finished' =>
     endif;
   enddefine;

To see the mechanics of TRAVERSE and in particular how that call of







Sep 13 00:04 1984  chapter.8 Page 11


TL(LIST) in the ELSE branch works, lets use TRACE -

       trace traverse;
       traverse(box);
       >traverse [shoes tins brushes]
       ** shoes
       !>traverse [tins brushes]
       ** tins
       !!>traverse [brushes]
       ** brushes
       !!!>traverse []
       ** finished
       !!!<traverse
       !!<traverse
       !<traverse
       <traverse

TRAVERSE is being called recursively. That is each time the
condition for completion 'LIST = []' is FALSE, TRAVERSE prints
something and then requests an execution of TRAVERSE with a
shortened (TaiLed) list. Eventually these successive shortenings
lead to an empty list [] whereupon no new call is made, and the
whole process 'unwinds' as shown by the '<TRAVERSEs' printed out by
TRACE.

You can think of each occurrence of '>TRAVERSE' as meaning something
like:

    'start a new process executing the TRAVERSE instructions'

It also indicates the input for the process. Meanwhile the PREVIOUS
PROCESS waits until the new process has finished, as signalled by
'<TRAVERSE' aligned below. The '!' marks are to help you see the
alignment. When the new process finishes, the previous one continues
from where it was in the 'script', or definition, for TRAVERSE.

TRAVERSE is typical of the way that list structure can be combined with
a recursively organised procedure.

Try TRAVERSE on CUPBOARD. What should it do?

Suppose you were to define TRAVERSE with the two instructions

       hd(list) =>
       traverse(tl(list));

reversed. What would TRAVERSE(BOX) do then? Try this version of
TRAVERSE, and TRACE it.

-- Searching a list -----------------------------------------------

A more discriminating version of TRAVERSE would be a procedure which
is looking for the presence of a particular item on a list

       define spotit(item, list) -> result;
         if  list = [] then







Sep 13 00:04 1984  chapter.8 Page 12


             false -> result
         elseif hd(list) = item then
             true -> result
         else
             spotit(item, tl(list)) -> result
         endif
       enddefine;

Now test the procedure

       spotit("tins", box) =>
        ** <true>

Use TRACE to find out exactly what is happening. Notice that the
value supplied for ITEM in this call of SPOTIT is the WORD

        "tins"

Also, instead of doing its own printing, SPOTIT produces OUTPUT, i.e.
whatever value is assigned to the variable RESULT.

What would happen if we had written

       spotit(tins, box) =>

and why?

Sometimes a program needs to know if something is in a list.

       IF so and so is in such and such THEN ...

This requires the use of a testing procedure which produces a
<TRUE>/<FALSE> RESULT like SPOTIT, unlike our previous procedures
which merely print something on the terminal. (Your programs can't
see the terminal.) Actually, the POP-11 system contains a library
function MEMBER which behaves like SPOTIT, so you can type

       member ("shoes", box) =>

SPOTIT unlike TRAVERSE 'returns a result' which it leaves on the
stack via the 'output local' variable RESULT. Although it is not
absolutely necessary to use an 'output local' variable, it is
advisable to do so for clarity. To see what is really going on you
can, as usual, trace the procedure.

       trace spotit;
       spotit("shoes", box) =>

This procedure is similar to but simpler than the procedure
'search_for' illustrated at the end of the previous chapter.

-- Defining DELETE recursively ------------------------------------

Often a LIST is returned as a result rather than TRUE or FALSE. Thus a
simplified version of the library procedure DELETE could be defined
thus:







Sep 13 00:04 1984  chapter.8 Page 13



       define delete(item, list) -> result;
         if list = [] then
             [] -> result
         elseif hd(list) = item then
             delete(item, tl(list)) -> result
         else
             [^(hd(list)) ^^(delete(item,tl(list)))] -> result
         endif
       enddefine;

Note the use of "^" to put one element into the list, and ^^(...) to
put some arbitrary number.

       delete(3, [1 17 3 42 30 3 19])=>
        ** [1 17 42 30 19]


To understand how delete works, we can TRACE it:

       trace delete;
       delete(3,[1 17 3 42 30 3 19])=>
       >delete 3 [1 17 3 42 30 3 19]
       !>delete 3 [17 3 42 30 4 19]
       !!>delete 3 [3 42 30 3 19]
       !!!>delete 3 [42 40 3 19]
       !!!!>delete 3 [30 3 19]
       !!!!!>delete 3 [3 19]
       !!!!!!>delete 3 [19]
       !!!!!!!>delete 3 []
       !!!!!!!delete []
       !!!!!!<delete [19]
       !!!!!<delete [19]
       !!!!<delete [30 19]
       !!!<delete [42 30 19]
       !!<delete [42 30 19]
       !<delete [17 42 30 19]
       <delete [1 17 42 30 19]
       ** [1 17 42 30 19]

The essence of DELETEs solution of the task lies in the way that it
constructs the resultant list starting from the [] list that it
reaches with the last call of

       !!!!!!!>delete 3 []

Remember that

       >delete 3 [42 40 3 19]

Means: 'starting a new process with inputs 3 and [41 40 3 19]'.

The previous process is suspended till this one has produced its
result, which is then used in the suspended process. The suspended
process has to remember where it was in the instructions for DELETE,
and what values it had for any of its local variables, e.g. ITEM,







Sep 13 00:04 1984  chapter.8 Page 14


LIST and RESULT.

DELETE removes ALL occurrences of the ITEM in the LIST offered to
it, so it should perhaps have been called DELETE-ALL. What would a
version that DELETEs just the first instance of ITEM it finds look
like?

Strictly, nothing is deleted from the original list. Rather a new
COPY is produced, minus the specified item. The original list is
unchanged. E.g.

   [1 2 3 2 1] -> list;
   delete(2, list) =>
   ** [1 3 1]
   list =>
   ** [1 2 3 2 1]

-- Iterating on lists -----------------------------------------

The main POP-11 iteration constructs were given in an earlier
chapter. Here we give a number of examples of iteration involving
lists. Using iteration we can easily perform a subset of the
operations previously illustrated using recursion. Iteration is
sometimes easier to understand, and can be more efficient (i.e.
easier for the computer). It has the disadvantage that you cannot
use TRACE to make explicit what is happening when the program runs.

There are many different forms of iteration over lists. The simplest
is a serial scan over the elements of the list. Here is a new
definition of TRAVERSE, using an UNTIL loop.

   define traverse(list);
      until list = [] do
        hd(list) =>
        tl(list) -> list
      enduntil;
    enddefine;
    traverse([a b c d]);
    ** a
    ** b
    ** c
    ** d

The action

  tl(list)->list

causes LIST to be given the value TL(LIST). TL is given the old
value as LIST. From that it produces as result a list containing all
but the initial element. The new list (the TAIL) is assigned to
LIST.

-- Using FOR ... IN ... DO .... with lists ------------------------

We often want to refer to each element of a list in turn, doing
something with it, such as adding to a running total. To avoid







Sep 13 00:04 1984  chapter.8 Page 15


constantly having to use an expression of the form 'hd(...)', we can
'package up' the instructions using a version of the FOR loop,
mentioned previously, i.e.
    FOR <variable> IN <list expression> DO .... ENDFOR

So, to add all the numbers in a list

    define addall(list) -> total;
        vars x;
        0 -> total;
        for x in list do
            x + total -> total
        endfor
    enddefine;

    addall([3 5 7 9]) =>
    ** 24

Here we don't bother to say explicitly
    tl(list) -> list

since the equivalent of this is implied in the FOR construct.

-- Using FOR in [% ..... % ] -------------------------------------

We could use the FOR construct to define the procedure DELETE,
which was given above in a recursive form. We use a variable, say
'x', to denote successive elements in a list. If the element is not
the same as the item to be deleted, then leave the element on the
stack. If all this is done inside the list brackets, using '%',
    [ %  .......    % ]

then the items left on the stack will be made into a list.

    define delete(item,list) -> result;
        vars x;
        [% for x in list do
             unless x = item then x /* left on stack */  endunless;
           endfor
        %] -> result
    enddefine;

    delete([a b], [[1 2] [3 4] [a b] [c d]]) =>
    ** [[1 2] [3 4] [c d]]

-- Iteration vs Recursion -----------------------------------------

Instead of using FOR, it is always possible to recurse on the TL of
the list. The recursive technique has the great advantage that
successive calls of the procedure can be TRACEd. Constructions
utilising loops (REPEAT, WHILE, UNTIL, FOR) do not admit of easy
monitoring through TRACE.

Often, however, it is very quick and easy, using VED, to temporarily
alter the definition so that each time round the loop the procedure
prints something (e.g. the value of 'x' in the last example). In a







Sep 13 00:04 1984  chapter.8 Page 16


system such as POPLOG altering and recompiling a procedure is so
fast that temporary changes for debugging purposes can be very much
more useful than in a conventional language.

Moreover, if a looping construct is used, then the list brackets,
[ ... ] ( or the vector brackets { ..... } ) can be used to collect
together all the items left on the stack into a list, if that is
desired. This is one of the features of POP-11 not available in
LISP.






















































Sep 13 00:12 1984  chapter.9 Page 1


CHAPTER.9

-- MATCHES: an introduction -----------------------------------

We have already seen how the equality symbol "=" can be used to
compare two lists. The operation MATCHES provides more sophisticated
facilities for matching lists against a partially specified pattern.
The symbol "==", which we have previously met as an equality symbol
can be used in patterns with an entirely different function, to
represent an unspecified number of unknown elements. For example
both the following complex expressions denote TRUE

    [who is the father of joe] matches [who is == ]

    [where is the father of joe] matches [where is == ]

The following also denote TRUE:

    [you are my favourite programming pupil] matches [== pupil]

    [the little dog laughed to see such fun] matches [== dog ==]

MATCHES is a procedure whose name is an infix operator.

It takes two arguments, both lists, and returns one result, a
boolean. The first argument is called the DATUM (what is given) and
the second the PATTERN, against which the datum is to be compared.
The pattern may contain special pattern elements, of which "==" is a
simple example. We shall see more examples of pattern elements
later. Notice the asymmetry: the pattern must be the second
argument, never the first.

To illustrate, here is a procedure which uses MATCHES to decide
whether a question wants a person or a place as its answer:

    define type_of_answer(list) -> type;
        if     list matches [who is ==] then
            "person" -> type
        elseif list matches [where is == ] then
            "place" -> type
        else
            "undef" -> type
        endif
    enddefine;

The procedure type_of_answer takes as its input a list, and produces
a word as its result. The word is one of "person" "place" "undef".
Notice the use of the multi-branch conditional form:
    if condition1 then
        action1
    elseif condition2 then
        action2
    else
        default action
    endif








Sep 13 00:12 1984  chapter.9 Page 2


We can test the above definition thus:
    type_of_answer([who is your father]) =>
    ** person

    type_of_answer([where is your father]) =>
    ** place

    type_of_answer([is Joe your father]) =>
    ** undef

"undef" is a word often used in in POP-11 to indicate something
unknown.

Of course, this definition is not at all adequate to recognising
requests for information about persons or places, e.g.

    type_of_answer([where was joe born]) =>
    ** undef

The matching procedure MATCHES is used by the database procedures,
ADD REMOVE PRESENT LOOKUP FLUSH and FOREACH. Further details are
provided in a later section.

-- Exercise ---------------------------------------------------

Using the previous definition as a model, define a procedure called
FRIENDLY, which takes a list of words as input, and produces a
result which is TRUE, or FALSE or UNDEF. The result should be TRUE
if the list contains the words 'LIKES YOU' and FALSE if the list
contains the words 'HATES YOU', and UNDEF if it contains neither.
The definition can start:
    define friendly(list) -> result;

Hint: you'll need to use "==" as a pattern element more than once in
the same pattern.

If you have access to a machine running POPLOG you should test your
definition with commands like:

    friendly([everybody hates you today]) =>
    friendly([father christmas likes you ]) =>
    friendly([I can not bring myself to like you]) =>

What results should these print out?


-- The matcher arrow "-->" ------------------------------------

The matcher arrow is often very useful when you are sure two things
will match, but you want to use the matcher to examine the contents
of one of them.

"-->" should not be confused with "->". The latter is the assignment
arrow.

The infix operation "-->" could have been defined thus:







Sep 13 00:12 1984  chapter.9 Page 3



    define 8 datum --> pattern;
        unless datum matches pattern then
            mishap(datum,pattern,2,'NON MATCHING ARGUMENTS FOR -->')
        endunless
    enddefine;

The '8' in the procedure heading indicates that an infix operation
of precedence 8 is being defined.

This definition looks as if it doesn't do anything when the datum
matches the pattern. We shall see that, on the contrary, it can be
used to 'decompose' a list.

The simplest use of '-->' is to check that a list has a certain format:

    list --> [junction == ];

checks that LIST starts with "JUNCTION". If not, an error occurs.

        [a b c d] --> [junction ==];

        ;;; MISHAP - NON MATCHING ARGUMENTS FOR -->
        ;;; INVOLVING:  [a b c d] [junction ==]
        ;;; DOING    :  --> compile

The operation --> can also be used to decompose a list, i.e. to assign
some of its components to variables.

    vars first, second, rest;
    list --> [?first ?second ??rest];

causes an error if LIST has fewer than two elements, otherwise gives
FIRST the first element, as its value, SECOND the second element,
and REST a list containing all the remainder.

Here's an example:

    vars first, second, rest;

    [mary had a little lamb] --> [?first ?second ??rest];

    first =>
    ** mary

    second =>
    ** had

    rest =>
    ** [a little lamb]

Notice the different effects of "?" and "??". The former means,
roughly "match ONE element", the latter means, roughly "match any
number".

-- Findroom revisited -----------------------------------------







Sep 13 00:12 1984  chapter.9 Page 4



We can illustrate the use of the matcher to simplify the definition
of a searching procedure, by redefining the procedure 'findroom'
introduced in chapter 1, and defined thus:

    define findroom(name, list_of_lists) -> data;
        ;;; search list_of_lists for one starting with name
        for data in list_of_lists do
            if data(1) = name then
                return();       ;;; i.e. stop the procedure
            endif;
        endfor;
        ;;; produce a mishap message
        mishap('DATA NOT FOUND', [^name ^list_of_lists])
    enddefine;

Compare this with the following:

    define findroom(name, list) -> data;
        vars len, breadth, height;
        if list matches [ ==  [^name ?len ?breadth ?height] == ]
        then
            [^name ^len ^breadth ^height] -> data;
        else
            mishap('DATA NOT FOUND', [^name ^list])
        endif
    enddefine;

The line
        if list matches [ == [^name ?len ?breadth ?height] == ]

runs the operation called 'matches' with two inputs, the value of the
variable 'list', and the pattern on the right, which instructs the
matcher what to look for in the list. It says, look for any number of
elements (matched against "=="), then a list starting with the given
name and containing three other things, followed by any number of
elements (matched against "==" again).

Notice the difference between "?" and "^" here. " The searched-for
information is represented by the list [^name ?len ?breadth ?height]
where the symbol "^" says that the given name must be found. "^" can be
read as 'use the value of', whereas the occurences of "?" can be read as
'set the value of'. I.e. the three variables will be given values
depending on what numbers are found after the name, once the list with
the required name is found. If we had used "?name" instead of "^name",
then ANY name would have been accepted.

If the MATCHES operation produces the result TRUE, having found what is
required then the instruction after 'then' is obeyed, which ensures that
the output local 'data' has an appropriate value, to be returned as the
result of the procedure.

If MATCHES cannot find what is required in list, then it produces the
result FALSE, and the instruction after 'else' is obeyed, causing an
error message to be printed out.








Sep 13 00:12 1984  chapter.9 Page 5


Using the fact that "-->" will cause an error when a match fails, we
could adopt the even shorter definition:

    define findroom(name, list) -> data;
        vars len, breadth, height;
        list --> [ ==  [^name ?len ?breadth ?height] == ];

        [^name ^len ^breadth ^height] -> data;
    enddefine;


-- List pattern matching --------------------------------------

We now provide a more general motivation for the pattern matcher,
and give a complete account of its operation.

SPOTIT and DELETE use

   item = hd(list)

to accomplish their aims. But list representations of more complex
situations do not exhibit their significant features in terms of
single items considered in isolation. Rather the norm is one of a
context or co-occurence of elements. Thus we are much more likely to
want to know whether a list contains two designated elements
occurring in a particular order, or even whether it satisfies some
rather more complex condition. E.g. does the sentence start with a
noun phrase? For now we consider only the relatively simple cases.

Supposing we have this list

   [a b c d e] -> x;

A relevant test might be to establish whether it contains B and D
occurring in that order. Now

    member("b",x) =>
    ** <true>
    member("d", x) =>
    **<true>

tell us that both are present i.e.

    member("b", x) and member("d",x) =>
    ** <true>

but we know nothing of their relative positions in L nor indeed of
their intervening or surrounding context.

We can capture this ordering of B and D for example:

    x(1) = "b" and x(2) = "d"

which specifies that D should immediately follow B in the list. In
fact the relationship that does obtain in X has the form








Sep 13 00:12 1984  chapter.9 Page 6


    x(2) = "b" and x(3) = "d"

In this way we can specify any arbitrary patterning of elements in a
list structure. It will however  be very tedious to try all possible
combination of pairs of successive numbers. The situation gets even
worse if you merely want to test whether "D" occurs SOMEWHERE to the
right of "B", although you don't mind where exactly.

-- The matcher ------------------------------------------------

To meet this need there is a procedure called MATCHES that tests a
given list for the presence of some specified pattern. We use it
like this:

    list MATCHES pattern =>

-- Describing the shape of a list pattern ---------------------

The B, D example is of course but one of an infinite variety of
patternings that we might want to look for. So our specification of
a pattern has to be couched in a suitably descriptive language. The
pattern for 'B immediately followed by D' would be:

    [== b d ==]

But the 'B followed somewhere by D' pattern would be specified like
this:

    [== b == d ==]

Where '==' denotes any number of list elements (including no
elements). Thus all of these lists should meet that specification:

    [a b c d e]
    [b d]
    [b a a c d f]

To test a given list, say X, for presence of this specified pattern
we'd call MATCHES like this

    x matches [== b == d ==] =>
    ** <true>

What result would you expect from the following:

    x matches [a == e] =>
    x matches [a == d == e] =>

The pattern specification we've adopted clearly admits of a lot of
variation in X - its a rather sloppy fit: and often that is a useful
way of representing generality. There are a number of ways in which
we can tighten it up, when required. We might for example want just
one intervening element between B and D:

    x matches [== b = d ==] =>
    ** <true>







Sep 13 00:12 1984  chapter.9 Page 7



These two symbols == and = are basic descriptors of pattern shape
and we may think of them as 'Gobbling up' intervening list items. We
can call '=' Gobble-one and '==' Gobble-any.

Gobble-one and Gobble-any help us characterise the linear shape of a
pattern. We may also want to characterise its structural
organisation. For example that the first element in the target list
must itself be a list - as it is in CUPBOARD for example.

    cupboard matches [[==] blanket ==] =>
    ** true

And this device may of course be used to dig arbitrarily 'deep' into
a list structure.

The pattern is then a sort of picture with lots of missing details,
of the kind of list we are looking for.

-- Using variables in a pattern specification -----------------

So far we've described our patterns in very literal terms. i.e. that
there needs to be a "B" and a "D", or a list etc. In practice the
items we want to include in our specification may have been
constructed by other procedures (and as we shall see by procedures
that use MATCHES). Typically these items will be the value of
variables. If we write

    cupboard matches [box blanket ==] =>
    ** <false>

because the first element of CUPBOARD is not "BOX" but a list which
is the same as the value of the variable BOX. We need to enrich the
pattern specification language so as to distinguish between words
used literally and words used as variable names. We do this with the
up-arrow ^ prefix. Thus

    cupboard matches [^box blanket ==] =>
    ** <true>

The use of ^ (up-arrow) in the pattern specification here is
the same as that introduced earlier. Thus

    [box blanket ==] =>
    ** [box blanket ==]

But

    [^box blanket ==] =>
    ** [[shoes tins brushes] blanket ==]

And it is of course only this latter version that matches CUPBOARD. Had
the value of CUPBOARD been

    ** [shoes tins brushes blanket pillow]








Sep 13 00:12 1984  chapter.9 Page 8


then that MATCH would have failed.

We need to 'strip off' the list brackets of the value of BOX if we
are to match this new kind of CUPBOARD, and we can do this by using
a double up-arrow:

    [^^box blanket ==] =>
    ** [shoes tins brushes blanket ==]

To illustrate the power of MATCHES and the pattern language,
consider the following defintion of the procedure MEMBER, and
compare it with the definition of SPOTIT given earlier:

    define member(item, list) -> trueorfalse;
      list matches [== ^item ==] -> trueorfalse
    enddefine;

This uses the fact that MATCHES returns a 'boolean' result, i.e.
either TRUE or FALSE.

-- Retrieving details of the target list ----------------------

Thus far we have merely been concerned to establish whether a
particular target list meets some pattern specification. And so far
that specification only cited various list fragments embedded within
a context whose precise composition was not germane to the
recognition of this key configuration.

We may however want to know what that context is, when a match is
obtained. For instance, a sentence analysing program which finds a
verb in a sentence may want to know what came before and after the
verb. It is also used in programs which interrogate the POP-11
database not merely to see if a particular piece of information is
there, but also to find out exactly what it is. E.g. you may not
merely wish to find out if the database has an item of the form
    [age fred ....]

you may also want to know what the age is.

Thus in recognising the ordered co-occurrence of "B" and "D" in the list

    [a b c d e] -> x;

we might want to be 'told' what the value of the intervening list
element(s) is (are).

To set a variable say P to take on the value of  single list element
prefix the variable name with '?' Thus

    vars p;
    x matches [== b ?p d ==] =>
    ** <true>
    p=>
    ** c

Similarly to set the variable to be some sequence of list elements use







Sep 13 00:12 1984  chapter.9 Page 9


?? Thus

    vars q;
    x matches [a ??q d ==] =>
    ** <true>
    q=>
    ** [b c]

Think of "?" as "get ONE element" and "??" as get ANY elements", by
analogy with "=" and "==". Try the following, which gives LIST a new
value, then uses it:

    [i like talking to you] matches [i ??list you] =>
    ** <true>
    [you ^^list me?] =>
    ** [you like talking to me?]

This is typical of the sort of trick used by Eliza.

Whenever the MATCH fails because the specified pattern, e.g.
[A == D ==], is not that of X, the queried variables may have their
values altered as part of the process of determining that the match
fails.

The basic concept of MATCHing is that of an identity between some
element or elements of the target list and elements of the pattern
specification. We can generalise this by requiring that a target
element have some specified PROPERTY.

For example in the ELIZA world, the occurrence of a word indicating
reference to the family e.g. SON, FATHER, MOTHER, BROTHER etc in an
input sentence is an important response-determining cue. To detect
that set membership we can use a procedure as an affix to a queried
variable in the pattern specification. Thus

    vars x;
    [my father loved me] matches [== ?x:family ==] =>
    ** <true>

    [you remind me of my brother] matches [== ?x:family ==] =>
    ** <true>

where FAMILY is a (previously-defined) procedure that might take the
form

    define family(word) -> result;
      member(word, [son father mother brother]) -> result
    enddefine;

You can gain experience with MATCHES ?, ??, ^, ^^, and variables by
working through TEACH RESPOND on the computer.

See if you can work out how to use MATCHES to find the answers to
the exercises involving "^" and "^^" above.

-- Summary of match notations ---------------------------------







Sep 13 00:12 1984  chapter.9 Page 10



Basic format:

    list MATCHES pattern

Pattern specification can contain:

    1) [A B]
        literal words to be checked in the target list

    2) =
        The 'Gobble-one' spacer

    3) ==
        The 'Gobble-any' spacer

    4) ^A
        Put into the pattern an object which is the value of the
        variable A. That object will then be compared with the
        corresponding object in the target list.
       ^(<expression>)
        Put into the pattern whatever results from evaluation of
        the expressin.

    5) ^^A
        A MUST have a list as value. Put into the pattern all the
        elements of the list, for comparison with elements of the
        target list.

    6) ?A
        Set A to have value of single element in the matching
        target list.

    7) ??A
        Set A to have value of sequence of elements in matching target
        list.

    8)  ?A:TEST
        Only allow A to match an element such that TEST(A) is
        not FALSE.

    9) ??A:TEST
        Like (8), but the TEST is applied to a LIST of successive elements
        from the target list.

NOTE: If the predicate TEST in the last two cases returns not TRUE
but some other non-FALSE result, then the result will be assigned to
the variable A.


-- MATCHing on a corpus of lists - the DATABASE concept -------

The description of some task situation may take the form of a large
corpusof lists, representing propositions. For instance we might
know that B1, B2, ... etc are blocks, that each has a colour and a
size, and that some are on others. These facts could be represented







Sep 13 00:12 1984  chapter.9 Page 11


as a database consisting of a list of lists:
   [[b1 isa block]
    [size b1 big]
    [colour b1 green]
    [on b1 b2]
    .........
    ]

We could also describe the contents of an image in terms of which
objects are in it what their properties are, and how they are
related. The library program SEEPICTURE builds up just such a list
representation of a PICTURE pattern to provide a basis for
recognition.

-- Adding and removing database items -------------------------

Since this facility is often required, POP-11 provides a collection
of automatically loaded library procedures for manipulating lists of
lists. They all make use of a global variable 'database' which may
contain arbitray information.

We can build up a DATABASE using ADD

    vars database;
    [] -> database;
    add([a]);
    add([b]);

    database =>
    ** [[b] [a]]

Notice that items appear in reverse order to the order of ADDing.

More concisely  we can use ALLADD

    alladd([[c] [d]]);
    database =>
    ** [[d] [c] [b] [a]]

Complementing ADD and ALLADD we have REMOVE and ALLREMOVE.

    remove([c]);
    database =>
    **[[d] [b] [a]]

The order of items in a call of ALLREMOVE is not important i.e. it does
not need to reflect the ordering of the DATABASE

    allremove([[a] [b] [d]]);
    database =>
    ** []

The procedure REMOVE will remove at most one item from the database,
even if it is given a pattern which matches several. Thus
REMOVE([==]); instead of removing everything, removes just one item.
Moreover, REMOVE will generate a MISHAP if it doesn't find one item







Sep 13 00:12 1984  chapter.9 Page 12


to remove. Similarly, ALLREMOVE will generate a mishap if it can't
remove something for every element of the list of patterns given to
it as argument.

The procedure FLUSH is provided without these restrictions. FLUSH
deletes everything in the database that matches its argument, but if
there is nothing that matches, then FLUSH does nothing!

The argument given to FLUSH is a pattern specification, that is
FLUSH uses MATCHES to determine the list items that it will DELETE.
It is however very powerful in its action... it removes ALL the
matching DATABASE entries. Thus with the DATABASE [[D] [C] [B] [A]]
the action

    flush([=]);

clears the DATABASE, thus:

    database =>
    ** []

Thus FLUSH([=]) is equivalent in this situation to

    allremove([[a] [b] [c] [d]]);

Whenever the database contains only one-element lists

    flush([=]);

will remove them all.

Similarly

    flush([==]);

will empty the database no matter what is in it, and is therefore
equivalent to

    [] -> database;

-- What was removed? ------------------------------------------

After using FLUSH or REMOVE the variable IT will hold the item last
removed. E.g.

    add([dogs like meat]);
    remove([dogs like == ]);
    it =>
    ** [dogs like meat]

The procedure ALLREMOVE, uses the variable THEM instead. This will
be a list of all the items removed. Similarly, ADD updates IT, and
ALLADD records things in THEM.

-- Finding items in the database ------------------------------








Sep 13 00:12 1984  chapter.9 Page 13


Perhaps the most commonly used procedure is PRESENT which takes a
pattern and starts MATCHing it against every database item. If the
match is ever successful then the item is returned as the result of
PRESENT otherwise the result is false.

    alladd([[a b c d] [d c b a] [a b d c]]);
    present([== b ==]) =>
    ** [a b d c]
    present ([== b c]) =>
    ** <false>

Notice that PRESENT finds the 'first' matching item. PRESENT is
frequently employed in a conditional e.g.

    if present(pattern) then action

The 'IF... THEN' construction 'uses up' the value returned before
THEN ie. try

    if present([== b ==]) then => endif;

This arises because POP11 treats the value returned by PRESENT
between "IF" and "THEN" as <TRUE> or <FALSE>. For many purposes
however we will need to know what the matched item is for example to
use it in the THEN branch of the conditional. For this purpose the
DATABASE variable IT is set to have the value of the matching item,
when PRESENT finds something.

    if present([== b ==]) then
      it =>
      remove(it);
    endif;
    ** [a b c d]

Which is of course the MATCHed item that PRESENT found. REMOVE has
however REMOVEd it -

    database =>
    ** [[d c b a] [a b c d]]

Note that it found only ONE item, matching the pattern, and removed
it. FOREACH, explained below, shows how you can search for ALL items
matching some pattern.

-- Retrieving values from within an ITEM ----------------------

Since all of the apparatus of MATCHES is utilised in those DATABASE
Functions, PRESENT can be used to set values of appropriately
queried variables in the pattern specification.

    vars x;
    present([?x b ==]) =>
    ** [a b c d]
    x =>
    ** a








Sep 13 00:12 1984  chapter.9 Page 14


Notice that if "?" or "??" is used before a word in a pattern, then
that word should be declared as a variable name. Hence the "VARS X;"
above. If the variables in patterns are not declared to be local, to
the procedures which use them, then different procedures can mess
each other up. This applies to procedures which use MATCHES or any
of the database operations PRESENT, FLUSH, LOOKUP, REMOVE, etc.

We do not always want the matching item. Sometimes we will know that
the item is present in the DATABASE and want only the value of some
fragment of it. For this purpose the procedure LOOKUP is provided.
It does not return <TRUE> or <FALSE> but merely sets the value of
queried pattern variables when a match is found.

    lookup([?x b ==]);
    x =>
    ** a

In the event of no match being found an error will result

    lookup([?x == c]);
    MISHAP:     LOOKUP FAILURE
    INVOLVING:  [?X == C]
    DOING:      LOOKUP

-- Retrieving all the items PRESENT which match a pattern -----

There will often be a need to find not just one matching item in the
DATABASE, (or to set the value of queried pattern variable for just
one matching item) but to find all of them. For this purpose the
looping construct FOREACH is provided:

    foreach [== b ==] do
      it =>
    endforeach;
    ** [d c b a]
    ** [a b c d]

Note that FOREACH is a 'syntax' word (like IF and DEFINE), not a
procedure name, and hence the pattern specification that follows
need not be enclosed in round brackets '(' ')'.

The general form of FOREACH is
    FOREACH <pattern> DO <action> ENDFOREACH;

For example, to print out every item in the database representing
something blue:

    vars x;
    foreach [??x is blue] do
        x ==>
    endforeach;

Inside the <action> the variable IT is available to represent the
database item which has matched the pattern. E.g. suppose you have
various database entries of forms:
    [p1 is a person]







Sep 13 00:12 1984  chapter.9 Page 15


    [b3 is a block]
    [c5 is a cat]

etc. Then, to print out all the blocks do:
    foreach [??x isa block]
    do      x =>
    endforeach;

you can use "[%" and "%]" to make a list of all the blocks:

    [% foreach [??x isa block]
       do      x
       endforeach
    %] -> blocks;

Each time round the value of X is left on the stack and the [%...%]
brackets make a list of all of them. The variable IT can be used
each time round the loop to refer to the database entry which was
found to match the pattern given after FOREACH.

FOREACH can be followed by IN to specify a list other than DATABASE to
search in, i.e.
    FOREACH <pattern> IN <list> DO <action> ENDFOREACH;



If you have access to a working POPLOG system you can get more
information and examples in:
    TEACH MATCHES; TEACH DATABASE; TEACH FOREACH; TEACH RIVER2;

-- Checking a set of patterns against the database ------------

Just as ALLADD and ALLREMOVE can be given a list of patterns to add
or remove, similarly, ALLPRESENT can be given a list of patterns to
look for in the database. If it finds items for all of them it
returns a list of the found items (and also assigns it to the
variable THEM). Otherwise its result is false. E.g. to find a
grandson of TOM:

    alladd([
          [dick father harry]
          [tom father jack]
          [bill father tom]
          [jack father dick]]);

    vars x, y;
    if allpresent([[tom father ?x] [?x father ?y]]) then
      y =>
    endif;
    ** dick
    them =>
    ** [[tom father jack] [jack father dick]]

For more information on the database procedures see HELP ADD, HELP
PRESENT, HELP REMOVE, HELP FLUSH and HELP LOOKUP.








Sep 13 00:12 1984  chapter.9 Page 16


-- Forevery ---------------------------------------------------

Just as ALLPRESENT is a generalisation of PRESENT, so POP-11
includes FOREVERY which is a generalisation of FOREACH, and allows
some fairly powerful manipulations of the database. In particular,
we can find all possible combinations of a SET of patterns in the
database. E.g. to find all paternal grandfather relations, i.e. all
combinations of the form
    [?x father ?y][?y father ?z]

Here's an example

    alladd([
          [dick father harry]
          [tom father jack]
          [bill father tom]
          [dick father mary]
          [jack father dick]]);

    database ==>
** [[jack father dick]
    [dick father mary]
    [bill father tom]
    [tom father jack]
    [dick father harry]]

    vars x, y, z;
    forevery [[?x father ?y] [?y father ?z]] do
        [^x is the paternal grandfather of ^z] =>
    endforevery;
    ** [jack is the paternal grandfather of mary]
    ** [jack is the paternal grandfather of harry]
    ** [bill is the paternal grandfather of jack]
    ** [tom is the paternal grandfather of dick]

Note that FOREVERY made sure that the value of 'y' in the two patterns
was the same.

The permitted formats of FOREVERY are:

    FOREVERY <list of patterns> DO <actions> ENDFOREVERY;

    FOREVERY <list of patterns> IN <database> DO <actions> ENDFOREVERY;

When 'IN <database>' is omitted, then the value of the variable DATABASE
is used as the database.

Another example: find all the blocks and print out their colours:

    forevery [[?x isa block] [colour ?x ?col]] do
        [^x is a ^col block] =>
    endforevery;

Or to find all maternal grandfather relationships:

    forevery [[?x father ?y] [?y mother ?z]] do







Sep 13 00:12 1984  chapter.9 Page 17


        [^x is grandfather of ^y] =>
    endforevery;


In addition to these procedures the POP11 library contains some more
powerful procedures SCHECK and SCHOOSE, for matching a whole database
pattern against a database, and indicating whether the match was
partially successful, what was missing, what was surplus, etc. For
details see HELP SCHEMA.

Although the database procedures described here are very powerful
compared with what most programming languages provide. They are still
not as powerful as the facilities built into the language PROLOG. See
    W. Clocksin and C.S. Mellish
    PROGRAMMING IN PROLOG, Springer Verlag.
















































Jul  7 15:06 1984  chapter.p Page 1


CHAPTER.P

-- POSSIBLE FURTHER ADDITIONS: ------------------------------------

updaters

classes

chain, chainto, breakto, catch, jumpout, etc.

partial application

itemiser

character streams, discin, discout, etc.

recordclass

vectorclass

arrays

'logical' operations ~~ etc.

sysexit and related procedures, popexit, vedpopexit

properties

processes

words, the dictionary, identifiers, cancel

character codes

sections

autoloading

'fast_' procedures. Efficiency tricks

The garbage collector, popgcratio, popmemlim

libraries

private help (etc) libraries

error handling

interrupt handling, popready

timing facilities

debugging aids

printing








Jul  7 15:06 1984  chapter.p Page 2


file handling

pipes and mail boxes

dynamic lists

proglist, the compiler, macros, syntax words, and code planting
    procedures

VED as a general purpose front end

Calling external procedures

saved images

initialisation: init.p, vedinit.p vedinitfile, etc.

Syntactic sugar available
    switchon
    forms


A selection of useful or interesting library packages
    sets
    profile
    showtree
    vturtle/turtle
    grammar/tparse/facets
    format
    msblocks
    pascal
































Jul  7 15:06 1984  chapter.q Page 1



-- DCL or UNIX COMMANDS ---------------------------------------

For VAX VMS users:
DCL commands can be given by typing the dollar as the first symbol on the
line, e.g.

    $ show time

or
    $ dir *.p

For UNIX users: you can give a UNIX Shell command by typing a dollar
as the first symbol on the line, followed by the command, e.g.
    $ ls -l *.p

On UNIX if you use a percent symbol '%' instead of the dollar, you'll
get the CSHELL rather than the SHELL.

To switch temporarily to DCL or SHELL, type the dollar on its own, at
the beginning of a line. POP-11 will be temporarily suspended. You leave
DCL by typing Q. You leave the UNIX shell by typing the end of file
character used at your UNIX installation. After that you will return to
where you were in POP.
