In Pop-11 procedures (which are referred to by Lisp programmers as functions) are "first class objects". This is a phrase used by some computer scientists to characterise programming languages with rich facilities for manipulating procedures, in contrast with programming languages in which you can merely define procedures and then run (invoke, execute) them, but cannot do anything else with them: in the latter case procedures are not "first class" objects.
In Pop-11 you can do several other things with procedures besides defining them and running them. If P is a procedure, then:
o You can give P as input to another procedure (which is also possible in several other common languages e.g. Pascal). E.g. you can give the procedure sqrt as input to the procedure maplist, to get the square roots of a list of numbers thus:
maplist([4 16 25 36], sqrt) => ** [2.0 4.0 5.0 6.0]o You can assign P to one or more variables, and use those variables to invoke it:
vars my_sqrt; sqrt -> my_sqrt; my_sqrt(16) => ** 4.0o you can return P as the result of running another procedure
o you can store P in a datastructure, like a list or a vector
[^sqrt ^hd ^maplist] => ** [<procedure sqrt> <procedure hd> <procedure maplist>]o you can combine (or"compose" P with other procedures to form more complex procedures using the Pop-11 concatenation operator <>, as shown in a later section of this chapter. (See REF * PROCEDURE/'Generic Datastructure Procedures')
o you can combine P with some data to form a new procedure using "partial application". (See HELP * CLOSURES). For example, the built in Pop-11 procedure member, referred to in Chapter 1, takes some item and a list and decides whether the item is in the list. So if you have a list of colour words, you can define a procedure iscolourword by combining member with the list, thus.
vars colours = [red orange yellow green blue indigo violet]; vars iscolourword = member(% colours %);After that, iscolourword is a "Pop-11 closure", a combination of a procedure with some data, which can be treated as a new procedure, thus:
iscolourword("red") => ** <true> iscolourword("square")=> ** <false>o If P is defined inside another procedure Q, and accesses some lexical variables of Q, then you can (in some cases) form a "lexical closure" of P which is another procedure with associated data involving the values of the variables in Q at the time the closure was created. (See HELP * CLOSURES, HELP * LVARS/'lexical closures')
o You can give P a new updater, e.g. using the form:
<new_updater> -> updater(P);o You can use P as the updater of another procedure, e.g. using:
P -> updater(Q);Most of the points mentioned above have either been illustrated in previous chapters or will be explained below. See also REF PROCEDURE
These features make Pop-11 a very powerful programming language. In particular, the ability to re-use one procedure in a variety of ways to create new procedures, helps with the design of modular programs and also facilitates the creation of relatively compact, easily maintained, but very general programs.
This is closely related to, though distinct from the re-use of "methods" in object oriented programming (also available in Pop-11 in the FLAVOURS and OBJECTCLASS packages).
In addition to Pop-11 programs being able to use existing procedures and combine them to form new procedures according to the needs of the occasion, Pop-11 also allows a running program to create new procedures from procedure definitions. One way of doing this for a running program to compile a file of procedure definitions which will then extend the capabilities of the program. Another way is for a program to create a list of text items then apply the procedure popval to it. Popval is able to invoke the compiler to build a new procedure, or obey instructions in the list. For example this will create a new procedure called "greet":
popval( [ define greet(x); [hello ] => x => enddefine; ]);Popval can be given lists that have been created by programs rather than by the programmer. In this way a program can extend itself in a way that depends on the environment when it runs, rather than on the programmer having decided in advance what the extension should be. This can be a powerful learning mechanism.