AI twoaramminelaneuaees: reqiiriiiiments, ficilitik &itechniques Using LISP, PROLOGand POP-H by ALLAN
RAMSAY
R
esearch into AI over the last 25 years or so has had major impacts on the shape of current programming practices. Many extremely widely used techniques originated with AI workers, from the first existence of ‘high level’ languages, through dynamic storage allocation and garbage collection, to the use of property inheritance in rela-
Abstract: AI programming languages, such as LISP, PROLOG and POP-II, are always supported by sophisticatedenvironments. Such environments include, at the least, incremental compilation and recompilation, an editor, and debugging tools. Typical facilities included in AI programs are list processing, pattern matching and frames. A particularly importantfacility is functional programming, which marks the diffnence between AX and other languages. In choosing a language for a particular problem, you should be thinking in terms of which language will be the best base for building the language you really need. Keywords: data processing, artificial intelligence, programming languages. Dr Ramsay is a lecturer within the Cognitive Studies Programme at the University of Sussex.
8
0011-484x/85/040008-04$03.00
0
1985 Butterworth & Co (Publishers) Ltd.
tional databases. This is hardly surprising. AI researchers are constantly trying to construct systems at the edge of the, ‘complexity barrier’, programs that are so difficult to construct and maintain that it is almost as much as any one person can do to keep track of what is going on. Even worse, these programs are experiments, objects which will almost certainly be discarded as soon as they have been tested. If they work, then the principles they embody will be required as the basis of further experimentation. If they do not, they will have to be redesigned and reimplemented. People working in this way are very likely to come up with ideas about what they would like their programming language to do for them, since they have such a need for support from it. If the language does not do what they want, they will upgrade it so it does. So effort put into providing support tools does pay off. So what are these marvellous facilities the AI community is so proud of! They may be split into three categories: 0 environment
data processing
systems l l
built-in facilities freedoms
We will consider instances of all three, using examples from the three major AI programming languages, and POP-113 and LISP’, PROLOG’, from the AI programming environment POPLOG, which provides support for all three of these languages.
Environments AX programming languages are always supported by sophisticated environments. Minimally such an environment provides:
facility to redefine, recompile and relink parts of your program individually, without completely interrupting and destroying your current interactive session. Given incremental recompilation, particularly when it is supported by an integrated editor, you can slash the time of the EDITCOMPILE - LINK - LOAD - RUN CRASH - EDIT - . . . cycle. You do have to be disciplined - it is only too easy to spend your time ‘debugging’ a program which would benefit more from a long cool look and a complete redesign.
Integrated editors incremental compilation and recompilation, l an editor which is tailored to the relevant programmiIig language, and which can be invoked at any point during the course of a programming session, * a collection of debugging tools, also tailored to the programming language, to help you find out what your program is doing. l
A number of systems try to provide more sophisticated tools in addition to the basic set, e.g. programs to detect minor bugs4, programs which will detect and m-rect spelling errors’, and libraries of program fragments (‘cliches’) from which programs can be constructedh. Most of these more sophisticated tools are still rather experimental. They will probably move nearer to everyd.ay use in the near future, but for the moment the more basic items are more significant.
AI languages are interactive. You type commands at them, then they compile or interpret them and execute them immediately. Just like BASIC. This facility makes if possible to test your programs extremely quickly and easily. Incremental recompilation is probably even more useful. This is the
VOW27 no 4
map 1985
Despite the benefits of incremental compilation and recompilation, it is not a good idea to sit down at the terminal for an hour or two, typing in code straight to the compiler and keeping no record of what has been done. It is still necessary to develop files of program text which will be there ready for further development next time we come along. What is needed is an editor which can be used during the course of an interactive session without interrupting the interaction too much. The editors provided within AI programming environments can be called up at any time and used to edit any part of the running program, with just that part being recompiled and relinked without interruption of the session. These editors also always embody knowledge of the language(s) supported within the environment. For example LISP ‘structure editors’ provide a wide range of commands for manipulating the nested list structure which constitute LISP programs, while the POPLOG screen editor VED provides commands orientated towards the structure of programs written in any of POP-II, PROLOG or LISP.
Furthermore these editors tend to be written in the supported language, so that it is easy for users to write commands that suit their own per-
sonal needs layout commands, commands to plant program cliches to be filled in, whatever they want.
Debugging aids One of the advantages that interactive program development is supposed to bring is rapid, easy debugging. This does not come free, as it has to be supported. The main point is to ensure that run-time error handling is extremely robust, and is as informative as possible. The ‘reason that the error handler has to be informative is self-evident, but the need for robustness may require some elaboration. The point is that it is no good allowing a user to develop a program by trying it out interactively if the moment he or she makes a mistake it types ??? ILL 606755
MEM
REF
AT USER
PC
and exits to the monitor, leaving the user with a core dump to investigate, at most. What the user wants is for the program to suspend execution, allowing investigation of the problem in terms of program-level concepts such as variable values, data structures, details of the current stack of procedure calls, and so on. When the user has discovered what was wrong, he or she will quite probably want to make some changes to the program and try again from the point at which the error occurred. This means that the most important of all debugging tools is an error handler which will trap all run-time errors within THE SYSTEM. The other tools that are often provided, such as facilities for tracing and single-stepping procedure calls for inspecting their arguments on entry and exit, are convenient. Safe errorhandling is crucial. It is worth noting here that debugging tools, like editors, are nearly always written in the supported language, and as such may easily be
9
adapted selves.
or extended
by users them-
Facilities Many AI programs make use of similar underlying techniques, e.g. list processing, pattern matching, inheritance hierarchies. Many of these techniques are so widespread (and so difficult to implement well) that they have become incorporated in the languages used for AI. Typical facilities include the following: l l l
list processing pattern matching frames
List processing Solutions to AI problems often involve the creation of large numbers of data structures to act as intermediate representations on the way to the final result. For instance, language processing systems use parse trees, vision systems use descriptions of picture features and planning algorithms use descriptions of intermediate world states. Neither the number nor the shape of these objects can be predetermined, beyond saying that their constituents may very easily be similarly unpredictable objects. Linked lists have to be found to be so suitable for implementing these things that all AI languages provide them as a basic resource. Furthermore, because the ways in which they get used are so potentially intricate, it is recognized that users cannot be expected to look after the eventual fate of these entities and their components for themselves. AI languages provide a storage management system which allows users to ask for structures as and when they want them, and then tidies up when they have finished with them.
Pattern matching AI programs make extremely heavy use of pattern matching, both for deciding what to do and for extracting
10
information from structures. Such heavy use, in fact, that powerful matching algorithms are generally provided as built-in facilities. PROLOG actually uses the ‘unification’ pattern matching algorithm as part of its basic execution strategy. LISP and ~0~11 simply provide pattern matching as an option. To see just one extremely simple example of what you can do given a good pattern matcher, consider the following fragment of POP11:
READLINE( ) + TEXT; IF TEXT MATCHES [I ??WORDS YOU] THEN PR([WHY DO YOU -*WORDS ME]) ELSEIF . . . This says that if some text consisting of the word ‘I’, followed by any number of items, followed by the word ‘you’ is input by a user, then it may be appropriate to output a response consisting of the words ‘Why do you’, followed by the items the user typed between ‘I’ and ‘you’, followed by ‘me’. This simple use of the pattern matcher would enable the machine to respond to inputs like ‘I hate you’ and ‘I want to kill you’ with ‘Why do you hate me’ and ‘Why do you want to kill me’. With this very simple example the machine would also respond to ‘I wish I had never met you’ and ‘I would like to kill you’ with ‘Why do you wish I had never met me’ and ‘Why do you would like to kill me’. There is, after all, more to language processing than pattern matching.
Frames It is widely argued that some of the knowledge used by AI programs should be organized as collections of facts relating to specific entities and classes. Minsky’s classic paper7 presents the notion of a ‘frame’ a collection of assertions, rules, and
defaults which together embody everything that is known about an entity. This notion has become so important that most AI languages come with some minimal implementation built in, although since everybody has different ideas about the fine details of how a frame should look, the minimal version usually gets elaborated before it is used. The above is a far from an exhaustive list of the things which an AI programmer would expect to find provided as basic facilities of the language. It is intended simply to give some idea of the flavour of what you would expect to get. There is one more facility which is supported by AI programming systems, which is so important that AI work would be virtually impossible without it ‘functional programming’.
Functional programming: alternative control structures and embedded languages Supportive environments and built-in facilities are very useful, but they do not of themselves enable you to do anything which you could not have done without them. You might have found it hard work, you might have found it so complicated that you would never have managed to get there, but there is nothing in principle which you can do with these facilities and not without them. It is the fact that in AI languages the distinction between programs and data is blurred, which enables you to do things that you cannot do in other languages. In any of POP-~I,PROLOG and LISP, there is a special class of objects, called procedures, functions or clauses, which embody the actions that the program can take. They are special, in that they can be run/applied/invoked, which other data structures cannot. But they are also not special, in that they can be manipulated in many of the ways that any other data structures can. They can be passed as
data processing
systems arguments and results, they can be assigned as variable values, they can be kept in lists and tables, they can be taken apart into their constituents or constructed out of components which are the results of other parts of the program. This is one of the most importance consequences of basing these languages on mathematical theories which give precise descriptions of the ways that functional objects are created - it is easy and natural to treat such objects as data. This ability frees users immediately from the restrictive control structures envisaged by the designers of the programming language. Because users can perform arbitrary actions on procedures before finally deciding to run them, they can easily experiment with alternative control structures pattern-directed invocation, backward and forward chaining, backtracking, coroutining, whatever you want. Language design is open to anyone aho can program in one of these languages. It is no longer an arcane activity which only extremely experienced and sophisticated programmers can take part in. Furthermore, experimenters can make use of any of the facilities of the underlying language at any point. They do not. have to write their own storage management systems, their own I/O routines or their own code generators, since they can use those provided for the basic language. All they have to do is write code to manipulate procedure records (functions, clauses) in the way they want rather than the way the system itself usually uses them. This means that users are no longer forced to fight the way the system does things if a problem requires them to be done a different way. IJsers can now attack the lower levels of a large problem by thinking about a language which would be convenient for this particular domain, knowing that if they discover that there is something suitable then they can easily implement it.
~0127no 4 may 1985
Large numbers of the major advances in AI make use of this fact. Particular control structures for expert systems, schedulers for allocating resources to collections of cooperating knowledge sources and simulations of parallel processors have all been used to simplify the descriptions of problems and hence make them more tractable. All these systems have been made possible by the fact that functional programming languages enable the user to experiment with alternative ways of organizing control without having to construct an entire programming language. Differences
between
systems
When you come to make decisions about AI programming systems, you have to consider a number of different issues. The first point to remember is that you are not just getting a programming language, you are (or should be) getting a programming environment support tools and standard facilities as well the bare programming language. The standard facilities should be no trouble, since nearly all systems support nearly all of them. The support tools are more difficult to assess without considerable practice with the system concerned, since some of them (e.g. LISP structure editors, PROLOG tracing facilities) are distinctly aimed at those aspects of the language in question which are the most unfamiliar. These tools are extremely useful. They have all been designed and implemented by regular users of the relevant languages as direct responses to their own experience, but until you have used the systems enough to have experienced roughly the same phenomena, you will not be able to assess them. The other important point is that you should be wary of judging an AI language in terms of its immediate appropriateness for your problem. If you are thinking about problems which are complex enough to require
then no single preAI techniques, existing language is going to be suitable. You have to think in terms of the ease with which the language is going to enable you to implement the language that you do really require. There is still going to be some question about which of the available languages will be better as a basis for the exercise of building a new language. This cannot be decided until the properties of the new language have been established by study of the problem area within which it is to be used. The most that can be said until this is done is that POP-I 1 and LISP are suitable for certain sorts of task, and PROLOG for others; and that perhaps a system like POPLOG? which supports all three languages, is the best thing to use, since otherwise your original investment in the system may constrain you to do things in unsuitable ways simply because that is the way the system makes it easy to do them. References Winston,
PH
and Hann, BKP Wesley (1981) Clocksin, WF and Me&h, CS Programming in PKOI,OG SpringerVerlag (1981) Barrett, R, Ramsay, AM and Sloman, A POP-II: a practical language for artificial intelligence Ellis-Horwood (forthcoming September 1985) Ramsay, AM ‘Type-checking in an untyped language’ Interna t . J . Man-machine Comm. No 20 (1984) Moon, D MACLISP reference manual MIT (1974) Waters, RC ‘The programmer’s apprentice: knowledge-based program editing’ IEEE Transactions on sqfi. eng. Vol 8 No 1 (1982) Minsky, M ‘A framework for representing knowledge’ in ed Winston, PH The psychology of computer q wsion McGraw-Hill (1975) LISP Addison
Cognitive Studies Programme, University of Sussex, Falmer, Brighton RN1 9QN.
11