fiore@hope.UUCP (David Fiore) (11/08/86)
This is the documentation to PD PROLOG. The next file contains the uuencoded program. Cut on the dotted line and print out the resulting file. ================================Cut Here================================= A.D.A PROLOG Documentation Version 1.5 for the Educational and Public Domain Versions June 23, 1985 Copyright Robert Morein and Automata Design Associates 1570 Arran Way Dresher, Pa. 19025 (215)-646-4894 The public domain PD PROLOG system has been contributed to the public domain for unrestricted use with one exception: the object code may not be disassembled or modified. Electronic bulletin boards and SIG groups are urged to aid in giving this software the widest possible distribution. This documentation may be reproduced freely, but it may not be included in any other documentation without the permission of the author. We are pleased to present the second major version of PD PROLOG, version 1.5. The memory requirements are somewhat greater than the original, since it is uses the large memory model. It compensates in thoroughness. The memory requirement is about 200K bytes of TPA, and it will benefit from up to 240k bytes. The availalble workspace is 100K bytes. We hope that you'll get some fun out of this PROLOG. It will afford you exposure to THE fifth generation language at the cost only of some intellectual effort. The motive is perfectly explicable: We want you to think of Automata Design Associates for fifth generation software. It also gives us a nice warm feeling. The memory requirement is 200 k of transient program area, plus whatever space is needed to execute programs from within PROLOG. DOS or MSDOS 2.0 are required. There are no features requiring IBM PC architecture. Automata Design Associates specializes in software for artificial intelligence and robotic applications. A PROLOG language system is available in various configurations. A LISP interpreter will be introduced in March of 1985. There are five versions of PROLOG available from Automata Design Associates. All of them run under the MSDOS or PCDOS operating systems. Other environments will be supported soon. .Public Domain PROLOG This serves to further the general awareness of the public about PROLOG. It also is an excellent adjunct to anyone learning the language. Most of the core PROLOG described by Clocksin and Mellish in the book Programming In PROLOG is implemented. Trace predicates and I/O redirection are not. .Educational PROLOG At extremely modest cost this affords an educational institution or individual a PROLOG system which provides the maximum available programming area available within the 8086 small programming model. Tracing, a debugging aid, allows monitoring a program as it runs. User settable spy points selectively allow this. Exhaustive tracing is also available. I/O redirection gives some file ability. An "exec" function allows the execution of a program or editor from within PROLOG, thus encouraging an interactive environment. Definite clause grammar support is now included. The cost of Educational PROLOG is $29.95. .FSM PROLOG A small increment in price adds full random access file capability. Character and structure I/O are allowed. The "asserta and "assertz" predicates are expanded and work with a clause indexing ability. One can assert clauses anywhere in the database under precise pattern matching control. A tree structured lexical scoping system and floating point arithmetic are other enhancements. The cost of FSM PROLOG is $49.95 .VMI PROLOG -- Virtual Memory (Replaces type VMS) At reasonable cost the addition of virtual memory gives an expansion of capabilities of an order of magnitude. The database on disk is treated transparently. No special provisions need be made by the user. Virtual and resident databases may be mixed. A unique updating algorithim preserves the format of the database as typed by the user while making only those changes necessary to make it equivalent to the database in central memory. The cost of VMI PROLOG is $99.95 A.D.A. PROLOG is a remarkable fifth generation developement tool for the implementation of intelligent strategies and optimized control. It is both the kernel for applications of virtually unlimited scope and a sophisticated developement tool that multiplies the productivity of the programmer many times. With a cost/performance ratio exceeding that of any other product and a compatibility insured by compliance to the Edinburgh syntax, performance is enhanced by numerous extensions, many of them invisible to the user. A quick overview of some of the features discloses: 1) Invisible compilation to a semantic network preserves the flexibility of the interpreted mode and the speed of a compiler. The programmer can compile and recompile any portion of a module at any time. The edit/compile/test cycle is short and free of strain. An interface is provided to an editor of choice. 2) Floating point arithmetic with a full complement of input and output methods, transcendental and conversion functions. 3) Virtual memory. Module size and number is unrestricted. Resident and virtual modules may be coresident. Compilation is incremental. The cache algorithim is sophisticated. Changes made in the database can be updated to disk by a single command. 4) A powerful exec function, and acceptance of stream input make integration into applications practical. 5) Many additional built-in predicates enhance the efficiency of the system. 6) Debugging facilities let you see your program run without any additional generation steps. 7) Totally invisible and incremental garbage collection. There is NEVER any wait for this function. The cost of this system is $200 for the MSDOS version. Half the cost of any A.D.A. PROLOG interpreter may be credited to the purchase of a higher level version. The full cost of VMS prolog may be applied to the purchase of VMI or VML PROLOG. Updates to a particular level product vary from $15.00 to $35.00. Run-time Packages Software developers wishing to integrate an A.D.A. product into their system should inquire about specialized run-time packages available at reasonable cost. Technical Information Technical information may be obtained at (215) - 646- 4894 Perhaps we can answer the following questions in advance: There is no support for: APPLE II, Atari, Commodore, or CPM 80 . Other machines from these manufactures may be supported in the future. The public domain version is available from the organizations who distribute such software. It is not available from us. The MSDOS products are available on 5" and 8" diskettes. To Place Your Order: You may place your order at either of the following numbers: (215)-646-4894 - day and night. (215)-355-5400 - 9 A.M. to 5 P.M., Eastern Standard Time Resellers should call (215)-646-4894 for information. Returns The software may be returned within 30 days of purchase for a full refund. This applies whether or not the software has been used. We do ask that manuals, disks and packaging be returned in excellent condition. without Knowing What You're Doing We strongly advise that you purchase the book Programming in PROLOG by Clocksin and Mellish, publisher Springer Verlag, 1981. For the impatient we give some advice. Type the demonstration program you wish to run. There must be at least one entry point within the program. Note: Please understand that these are demonstrations programs. Regarding user interface, they are poorly written. You will probably have to read Clocksin and Mellish to appreciate that the following examples of input are not equivalent: "yes." , "yes" . The animals program - "animal" Most of the examples require C & M for comprehension. The program "animals", however, can be appreciated by anyone. It is a traditional example of an expert system. We had hoped to include the animals program on disk, but we have found to our dismay that the version which we used is allegedly copyrighted by the implementors of PROLOG 86. Don't be surprised - even "happy birthday" is copyrighted. We will simply point out that the November '84 issue of Robotics Age included a version of the animals game, which you can, at the risk of copyright infringement, type in. There is only one change that need be made. The "concat" function used in that program has arguments of the form: concat( [atom1, atom2,...], result ). In order to make the concat definition more closely resemble that of "name", which is described by Clocksin and Mellish, the argments have been reversed: concat( result, [atom1, atom2,...] ) Assuming that you have typed in the program and made the change just noted, the following steps are required to run it: Run the prolog.exe file. The prompt "?-" will appear. Type "consult( 'animals' ).<CR>". Here <CR> indicates you are to type a carriage return. The PROLOG system will load "animals" and compile it into an internal form. When the "?-" prompt appears PROLOG is ready to run the "animals" guessing game. The object of the program is to deduce the animal you are thinking of. To start it off type "help.<CR>". PROLOG will respond by asking a question. Because of the way the animals program is written, you must respond in a rigid format. You may type "yes<CR>", "no<CR>", or "why<CR>". Eventually the program will terminate with either a guess as to what animal you are thinking of, or a remark that the animal is not within its domain of knowledge. The program has learned0&a , however. You may run the program again to see what effect additional knowledge has on the program's behavior. The program fragment "console" shows how you may improve the console input routines of any of these programs. The Hematology Diagnosis Program - "hemat" Although the logical structure is not as sophisticated as that of "animals", it is interesting for several reasons: 1) The program evaluates numerical data to arrive at a diagnosis. 2) Although inaccurate, it demonstrates that useful question answering systems are not difficult to write in PROLOG. 3) There are some mistakes in the program, which only slightly impede its usefulness. This program uses structure input. Terminate all your answers with a period, as in "y.<CR>", or "no.<CR>". The starting point is "signs.<CR>". PROLOG will prompt you for signs of anemia. The program attempts to diagnose two varieties of a hemolytic anemia. The program could use a good working over by a hematologist and we would be delighted to collaborate. Prime Number Generator - "sieve" This program demonstrates that anything can be programed in PROLOG if one tries hard enough. Asking the question "primes( 50, L ).<CR>" causes a list of prime numbers less than 50 to be printed out. "Sieve" is heavily recursive and quickly exhausts the stack space of the small model interpreters. Grrules This is an example of the use of the definite clause grammer notation. PD PROLOG does not have this translation facility, but ED PROLOG and all of our other versions do. It is possible to perform the translations by hand if you have thoroughly read C & M. Then you would have the pleasure of asking: ?-sentence( X, [every,man,loves,a,woman], [] ). and having the meaning elucidated as a statment in the predicate calculus. For some inexplicable reason, demonstration programs are hard to come by. We are too busy writing PROLOG fill this gap. We will reward the contribution of "cute" sample programs with the following: 1) A free copy of type VMS virtual memory PROLOG 2) The sample program will be published as an intact file together with whatever comments or advertisments the author may see fit to include, on our distribution disks. 3) Exceptional contributions may merit a copy of type VML large model virtual memory PROLOG which now incorporates a UNIX1 style tree structured domain system. Special Offer # 2 If you are a hardware manufacturer and would like a PROLOG language for your system, the solution is simple. Just send us one of your machines! Provided your system implements a "C" compiler, it will be ported in no time flat. ______ 1. Trademark of AT & T. You do not type in programs at the "?-" prompt. There is no built-in editor. The command "consult( user )" is accepted but does not cause PROLOG to enter an editing mode. We feel that the most universally acceptable editing method is for the user to use a text editor of choice, which can be invoked from within PROLOG by the "exec" predicate. Use Wordstar or your customary editor to write a program. Then run PD PROLOG and use the consult function to load the program. In all cases except PD PROLOG, you can run your editor without leaving PROLOG by use of the "exec" predicate. Running the Interpreter COMMANDS: Give commands in lower case. TO RUN: Invoke PROLOG.EXE. After the "?-" prompt appears, type "consult( <filename><CR> )", where <filename> is the desired database. To exit, type "exitsys.<CR>" TO ASK A QUESTION: At the prompt, type "<expression>.<CR>", where <expression> is a question as described by Clocksin and Mellish. Be sure to terminate the question with a period. The question may be up to 500 characters long. TO INPUT A STRUCTURE AT THE KEYBOARD: The structure may be up to 500 characters in length. Be sure to terminate with a period. TO ASK FOR ANOTHER SOLUTION: If a solution has been provided, the PROLOG interpreter will ask "More? (Y/N):". Only if a "y" is typed will the interpreter perform a search. TO ABORT A SEARCH: Simply type the escape key. The interpreter will respond with "Interrrupted.", and return to the command prompt. TO LOAD ANOTHER DATABASE: Type "consult(<filename>).<CR>" The file name must have the extension ".PRO". It is not necessary to include the extension in the argument of consult. TO REMOVE A DATABASE: Type "forget(<filename>).<CR>" TO EXIT TO THE OPERATING SYSTEM: Type "exitsys.<CR>" The system is totally interactive; any commands the operator gives are and must be valid program statements. Statements must terminate with a period. All commands which take a file name also accept a path name. Any name which is not a valid PROLOG atom (refer to C & M) must be enclosed in single quotes. Thus one could say consult( expert ) but one would need single quotes with consult( 'b:\samples\subtype\expert' ). To exit the system, type "exitsys.<CR>" Atoms may contain MSDOS pathnames if they are enclosed by single quotes, ie., '\b:\samples\animal' . You may consult more than one file at a time. However, all names are public and name conflicts must be avoided. The order in which modules are loaded may, in cases of poor program design, affect the behavior. Command Line Arguments ED PROLOG accepts one command line argument, which is the name of a "stream" which replaces the console for input. The "stream" in MSDOS is a pipe or file which supplies input until end-of-file is reached. Control then reverts back to the console. To avoid noisy parser error messages when end-of-file is reached, the last command in the file should be "see( user )." A Reference of Note With minor exceptions, the syntax is a superset of that described by Clocksin and Mellish in the book Programming in Prolog by W.F. Clocksin and C.S. Mellish, published by Springer Verlag in Berlin, Heidelberg, New York, and Tokyo. We shall refer to this book as "C & M". There are very few syntactical differences, mostly unrecognized and/or minor. When an operator is declared using the "op" statement, the operator must be enclosed in single quotes in the "op" statemen0&a t itself, if it would not otherwise be a legal Edinburgh functor. Subsequently, however, the parser will recognize it for what it is, except in the "unop" statement, where it must again be enclosed in single quotes. Variable numbers of functor paramaters are supported. A goal may be represented by a variable, which is less restrictive than the C & M requirement that all goals be functors. The variable must be instantiated to a functor when that goal is pursued. Rules which appear inside other expressions must be enclosed in parenthesis if the "," operator is to be recognized as a logical connective. All infix operators described by C & M, and user defined infix, prefix, and postfix operators with variable associativity and precedence are supported exactly as in C & M. The following built in predicates described by Clocksin and Mellish are supported. Those marked with asterisks have additional features: arg arithmetic operators: "+", "-", "*", "/", <, <=, >, >=, mod *asserta *assertz atom atomic call *clause clearops consult ! *debugging *display fail functor *get0 integer is list extraction operator: "|" listing logical connectives: ",", ";", mod name nl nodebug nonvar not notrace op *put *read *reconsult repeat retract see seeing seen spy tab tell telling told trace true var Description of the Modifications. call( <goal> ) The predicate as defined in C & M is obsolete. The purpose was to permit a goal search where the goal name was a variable instantiated to some functor name. A.D.A. permits writing of goals with such names, so the mediation of the "call" clause is no longer necessary. The "call" predicate may be trivially implemented for compatibility with the PROLOG definition call( X ) :- X. clause The function clause( X, Y ) has the new optional form clause( X, Y, I ). If the third variable is written, it is instantiated to the current address of a clause in memory. The only use of the result is with succeeding assertfa and assertfz statements. cut If the cut is the last clause of a search the user will not be queried "More? Y/N" for additional solutions. debugging "Debugging" prints a list of the current spypoints. After each name a sequence of numbers may appear, indicating the number of arguments that is a condition of the trace. The word "all" appears if the number of arguments is not a condition of the trace. Defines the user definable grammar of a functor. The definition conforms to that in C & M. We mention here a minor but important point. If <functor> is not a valid PROLOG atom it must be enclosed in single quotes when declared in the "op" declaration and when undeclared in the "unop" declaration. It is not necessary or legal to do this when the functor is actually being used as an operator. Declared operators are annotated in the directory display with their precedence and associativity. Output predicates display write print put These functions have been modified to accept multiple arguments in the form: print( <arg1>, <arg2>, <arg3>,... ) Thus, "put( a, b, c )" would result in the display of "abc". The names of some PROLOG atoms that may occur are not accepted by the PROLOG scanner unless surrounded by single quotes. This only applies when such an atom is read in, not when it is internally generated. Nevertheless, this presents us with a problem: We would like to be capable of writing valid PROLOG terms to a file. In some cases, it is necessary to add the single quotes. In other cases, such as human oriented output, they are an irritant. The modified definitions of the following predicates are an attempt at a solution: display Operator precedence is ignored, all functors are printed prefix and single quotes are printed if needed or they were supplied if and when the atom was originally input. write Operator precedence is taken into account and operators are printed according to precedence. Single quotes are printed under the same conditions as for "display." print Operator precedence is taken into account and operators are printed according to precedence. Single quotes are never displayed. This is a human oriented form of output and should never be used for writing of terms for the PROLOG scanner. read The functions "get0" and "read" have been extended to support input from a stream other than the one currently selected by "see". To direct output to a file or other stream, an optional argument is used. For example, "get0( char, <file name> )" or "get0( char, user )" would cause input to come from <file name> or the console. If the file has not already been opened, "get0" will fail. Atoms enclosed by single quotest, eg. '\nthis is a new line' can contain the escape sequences '\n', '\r', '\t' and '\''. If these atoms are printed by "display" or "write" they are printed just as they are. If they are printed by the "print" clause they are translated as follows: '\n' results in the printing of a carriage return and a line feed. '\r' results in the printing of a carriage return only. '\t' results in the printing of a tab character. '\'' allows the printing of a single quote within a quoted atom. The "portray" feature is not presently implemented. Description of the New Predicates clearops- Nullify the operator status of every operator in the database. concat( (<variable> | <functor>), <List> ) A list of functors or operators is concatenated into one string, which becomes the name of a new atom to which <variable> or <functor> must match or be instantiated. dir( option ) Provide an alphabetized listing to the console of atoms, constants, or open files. Without options, simply type "dir.<CR>". Options are: dir( pred ) - list clause names only. dir( files ) - list open files only. exitsys Exit to the operating system. forget( <file name> ) Make a database unavailable for use and reclaim the storage it occupied. ratom( <arg>, <stream> )- Read an atom from the input stream, to which <arg> matches or is instantiated. <stream> is optional. If <stream> is not given, the input stream defaults to the standar input. Input is terminated by a CR or LF, which are not included in the stream. Integer arithmetic is supported. Numbers are 32 bit signed quantities. The following arithmetic operators are supported: "+", "-", "*", "/", <, <=, >, >=, mod. Arithmetic operators must never be used as goals, although they may be part of structures. It is legal to write: X = a + b which results in the instantiation of X to the struture (a + b). But the following is not legal: alpha( X, Y ) :- X + Y, beta( Y ). Evaluation of an arithemtic expression is mediated by the "is" and inequality predicates. For instance, the following would be correct: alpha( X, Y, Z ) :- Z is X + Y. beta( X, Y ) :- X + 2 < Y + 3. Introduction Probably you have heard of the language PROLOG within the last year or so. You probably wondered the following things: 1) What does the name stand for? Names of computer languages are almost always acronyms. 2) What is it good for? 3) Why now? 4) Can I get a copy to play with? Congratulations! You obviously know the answer to the fourth question. We now respond to the other three. 1) The name stands for "programming in logic." This we shall elaborate on in depth later on. 2) PROLOG is good for writing question answering systems. It is also good for writing programs that perform complicated strategies that compute the best or worst way to accomplish a task, or avoid an undesirable result. 3) PROLOG was virtually unknown in this country until researchers in Japan announced that it was to be the core language of that country's fifth generation computer project. This is the project with which Japan hopes to achieve a domainant position in the world information industry of the 1990's. PROLOG is one of the most unusual computer languages ever invented. It cannot be compared to FORTRAN, PASCAL, "C", or BASIC. The facilities complement, rather than replace those of conventional languages. Although it has great potential for database work, it has nothing in common with the database languages used on microcomputers. Perhaps the best point to make is that while conventional languages are prescriptive, PROLOG is descriptive. A statement in a conventional language might read: if( car_wheels = TRUE ) then begin (some sort of procedure) X = X + 1; end and wheels. There are many relationships that hold. For instance, has( car, wheels ). has( car, quant(wheels, four) ). round( wheels ). Each of these statments is an independent fact relating cars, wheels, and the characteristics of wheels. Because they are independent, they can be put into a PROLOG program by programmers working separately. The man who is a specialist on car bodies can say his thing, the wheel specialist can have his say, and the participants can work with relative independence. And this brings to light a major advantage of PROLOG: PARALLEL PROGRAMMING!!! With conventional programming languages projects can still be "chunked", or divided between programmers. But efficiency on a team project drops drastically below that of the individual programmer wrapped up in his own trance. As the number of participants grows the need for communication grows geometrically. The time spent communicating can exceed that spent programming! Although PROLOG does not eliminate the need for task coordination, the problem is considerably simplified. It also provides the ability to answer questions in a "ready to eat form." Consider your favorite BASIC interpreter. Based upon the statements about cars and wheels previously given, could you ask it the following question? has( car, X ), round( X ). Does a car have anything which is round? The question instructs the PROLOG interpreter to consider all the objects that it knows are possessed by a car and find those which are round. Perhaps you are beginning to guess that PROLOG has the abilities of a smart database searcher. It can not only find the facts but selectively find them and interpret them. abbreviated one: {Car won't start} | | [Engine turns over](No) --> [Battery voltage](no)-\ (Yes) v | {Check battery} | [Smell gasoline](yes) --> {Try full throttle cranking} | (failure) /--------/ | (details omitted) The fault tree is easily programmed in BASIC. Later we shall show that PROLOG supplies a superior replacement for the fault tree. Though the tree is capable of diagnosing only the problem for which it was designed, PROLOG dynamically constructs the appropriate tree from facts and rules you have provided. PROLOG is not limited to answering one specific question. Given enough information, it will attempt to find all deductive solutions to any problem. PROLOG PRIMER I. Rules and Facts This is where you should start if you know nothing about PROLOG. Let us consider a simple statment in PROLOG, such as: 1) has( car, wheels ). This statement is a "fact. The word "has" in this statment is known either as a functor or predicate. It is a name for the relationship within the parenthesis. It implies that a car has wheels. But the order of the words inside the bracket is arbitrary and established by you. You could just as easily say: 2) has( wheels, car ). and if you wrote this way consistently, all would be well. The words has, wheels, and car are all PROLOG atoms. "Wheels" and "car" are constants. A database of facts can illustrate the data retrieval capabilities of PROLOG. For instance: 3) has( car, wheels ). has( car, frame ). has( car, windshield ). has( car, engine ). You could then ask PROLOG the question: 4) has( car, Part ). The capital "P" of Part means that Part is a variable. PROLOG will make Part equal to whatever constant is required to make the question match one of the facts in the database. Thus PROLOG will respond: Part = wheels. More?(Y/N): If you type "y" the next answer will appear: Part = frame. More?(Y/N): If you continue, PROLOG will produce the answers Part = windshield and Part = engine. Finally, you will see: More?(Y/N):y No. indicating that PROLOG has exhausted the database. Incidentally, when a variable is set equal to a constant or other variable, it is said to be instantiated to that object. Notice that PROLOG searches the database forwards and in this case, from the beginning. The forward search path is built into PROLOG and cannot be changed. An author of a program written in a prescriptive language is quite conscious of the order of execution of his program, while in PROLOG it is not directly under his control. The other major element is the rule which is a fact which is conditionally true. In logic this is called a Horn clause: 5) has( X, wheels ) :- iscar( X ). The fact iscar( car ) and the above rule are equivalent to 6) has( car, wheels). The symbol :- is the "rule sign." The expression on the left of :-is the "head" and on the right is the body. The variable X has scope of the rule, which means that it has meaning only within the rule. For instance, we could have two rules in the database using identically named variables. 7) has( X, transportation ) :- has( X, car ), has( license, X ). 8) has( X, elephant ) :- istrainer( X ), hasjob( X ). The variables X in the two expressions are completely distinct and have nothing to do with each other. The comma between has( X, car ) and has( license, X ) means "and" or logical conjuction. The rule will not be true unless both the clauses has(X, car) and has( license, X ) are true. On the other hand if there is a rule 9) has( license, X ) :- passedexam( X ). consider what PROLOG will do in response to the question: 10) has( harry, transportation ). (Notice that harry has not been capitalized because we do not want it taken as a variable. We could, however, say 'Harry' enclosed in single quotes.) It will scan the database and use (7), in which X will be instantiated to harry. The rule generates two new questions: 11) has( harry, car ). 12) has( license, harry ). Assuming that harry has a car, the first clause of (7) is satisfied and the database is scanned for a match to (12). PROLOG picks up rule (9) in which X is instantiated to harry and the question is now posed: 13) passedexam( harry ). If there is a fact: passedexam( harry ). in the database then all is well and harry has transportation. If there is not, then PROLOG will succinctly tell you: No. But suppose Harry has money and can hire a chauffer as any good programmer can. That could be made part of the program in the following way. The rule which PROLOG tried to use was: 14) has( X, transportation ) :- has( X, car ), has( license, X ). At any point following it there could be included another rule: 15) has( X, transportation ) :- has( X, money ). or simply the bald fact: 16) has( harry, transportation ). These additional rules or facts would be used in two circumstances. If at any point a rule does not yield a solution, PROLOG will scan forward from that rule to find another applicable one. This process is known as "backtracking search" and can be quite time consuming. If in response to the "More?" prompt you answer "y" PROLOG will search for an additional distinct solution. It will attempt to find an alternate rule or fact for the last rule or fact used. If that fails, it will back up to the antecedent rule and try to find an alternate antecedent. And it will continue to back up until it arrives at the question you asked, at which point it will say: No. "Antecedent" to a rule means that it gave rise to its' use. For example, (7) is the antecedent of (9) in the context of the question (16). II. Grammar It is a boring subject, but it must be discussed. All PROLOG statements are composed of valid terms, possibly a rule sign (":- "), commas representing conjunction ("and"), and a period at the very end. A term is a structure, constant, variable, or number. What is a structure? It is a kind of grouping: 1) Structures consist of a functor, and a set of objects or structures in parenthesis. 2) Objects are constants, variables, numbers, or lists, which we have not discussed yet. 3) A constant or functor must be a string of letters and numbers, beginning with a lower case letter, unless you choose to enclose it in single quotes ( 'howdy pardner' ), in which case you are freed from these restrictions. 4) A variable must be a string of letters and numbers beginning with a capital letter. 5) A functor may optionally have arguments enclosed in parenthesis , as in: hascar( X ) or hascar. An example: "has( X, transportation )." is a structure. You now know enough to write simple databases and interrogate them profitably. But before we examine more sophisticated examples, it will be necessary to add input and output to the language. There are built in functions which appear as rules which are satisfied once. Thus the statment: write( 'Hello world.' ). can be included on the right side of a rule: greetings( X ) :- ishuman( X ), write( 'Hello world.' ). You can also write "write( X )" where X is some variable. Note that 'Hello world.' is not enclosed in double quotes. Single quotes, which denote a constant, are required. Double quotes would denote a list, which is another thing entirely. Provided that a match to "ishuman" can be found, the builtin function "write" is executed and the message printed to the screen. The builtin read( X ) reads a "structure" that you input from the keyboard. More formally, we have read( <variable> or <constant> ) write( <variable> or <constant> ) If you write read( Input ), then the variable "keyboard" will be assigned to whatever is typed at the keyboard, provided that the input is a valid PROLOG structure. The builtin "read" will fail if instead of Keyboard we wrote read( baloney ), where "baloney" is a constant, and the user at the keyboard did not type exactly "baloney." When you input a structure in response to a "read" statement, be sure to end it with a period and an <ENTER>. There is a convenient way of putting the cursor on a new line. This is the builtin "nl". For example: showme :- write( 'line 1' ), nl, write( 'line 2' ). would result in: line 1 line 2 There is also a primitive form of input/output for single characters. It will be discussed later. Consider the "won't start" fault tree for an automobile: {Car won't start} | | [Engine turns over](No) --> [Battery voltage](no)-\ (Yes) v | {Check battery} | [Smell gasoline](yes) --> {Try full throttle cranking} | (failure) /--------/ | | /------------------------/ | | | | | [Check for fuel line leaks](yes)-->{Replace fuel line} | (no) | | | | | [Check for defective carburator](yes)--\ | (no) v | {Repair carburator} \----\ | | [Is spark present](no)-->[Do points open and close](no)-\ | (yes) v /----/ | {Adjust points} | /------------------------/ | | | [Pull distributor wire, observe spark](blue)--\ | (orange) v | | {Check plug wires & cap} | | | [Measure voltage on coil primary](not 12V)--\ | (12V) v | | {Check wiring, ballast resistor} | | | [Check condenser with ohmmeter](conducts)--\ | (no conduction) v | | {Replace condenser} | | | [Open and close points](voltage not 0 - 12)--\ | (voltage swings 0 - 12) v | | {Fix primary circuit} | | | {Consider hidden fault, swap components] | | \-------{Call a tow truck!!} represents a decision point fragment of the tree. The PROLOG interpreter dynamically assembles the tree as it attempts a solution. 'car wont start' :- write( 'Is the battery voltage low?' ), affirm, nl, write( 'Check battery' ). 'car wont start' :- write( 'Smell gasoline?' ), affirm, nl, 'fuel system'. 'fuel system' :- write( 'Try full throttle cranking' ). 'fuel system' :- write( 'Are there fuel line leaks?' ), affirm, nl, write( 'Replace fuel line.' ). 'fuel system' :- write( 'Check carburator' ). 'car wont start' :- write( 'Is spark present?' ), not( affirm ), nl, 'no spark'. 'no spark' :- write( 'Do points open and close?' ), not( affirm ), nl, write( 'Adjust or replace points.' ). 'no spark' :- write( 'Is the spark off the coil good?' ), affirm, write( 'Check plug wires and cap.' ). 'no spark' :- write( 'What is the voltage on the primary of the coil: ' ), read( Volts ), Volts < 10, nl, write('Check wiring and ballast resistor.'). 'no spark' :- write( 'Does the capacitor leak?' ), affirm, write( 'Replace the capacitor.' ). 'no spark' :- not( 'primary circuit' ). 'primary circuit' :- write( 'Open the points. Voltage across coil?:'), nl, read( Openvolts ), Openvolts < 1, write( 'Close the points. Voltage across coil?:'), read( Closevolts ), Closevolts > 10, nl, write( 'Primary circuit is OK.' ). 'no spark' :- write( 'Consider a hidden fault. Swap cap, rotor,points,capacitor.' ). 'Car wont start' :- write( 'Get a tow truck!!' ). --End program-- The above is a simple example of an expert system. A sophisticated system would tell you exactly the method by which it has reached a conclusion. It would communicate by a "shell" program written in PROLOG which would accept a wider range of input than the "valid structure" required by the PROLOG interpreter directly. Consider a shopping list given you by your wife. It is a piece of paper with items written on it in an order that probably symbolizes their importance. At the top it may say EGGS!!!, followed by carrots, hamburger, and finally a flea collar for the dog, if you can find one. In PROLOG such a list would be written: 1) [eggs, carrots, hamburger, fleacollar] The order of a list is important so that eggs and carrots cannot be reversed and PROLOG be uncaring. Let us put the list in a structure: shopping( [eggs, carrots, hamburger, fleacollar] ). Then if you wished to isolate the head of the list you could ask the question: shopping( [ Mostimportant | Rest ] ). and PROLOG would respond: Mostimportant = eggs, Rest = [carrots, hamburger, fleacollar]. The vertical bar "|" is crucial here. It is the string extraction operator, which performs a combination of the CDR and CAR functions of LISP. When it appears in the context [X|Y] it can separate the head of the list from the rest, or tail. You may have gained the impression that PROLOG is a rather static language capable of answering simple questions, but it is far more powerful than that. The string extraction operator is the key. It permits PROLOG to whittle a complex expression down to the bare remainder. If the rules you have given it permit it to whittle the remainder down to nothing, then success is achieved. An example of this is the definition of "append." Let us suppose you have not yet done yesterday's shopping, let alone today's. You pull it out of your wallet and sootch tape it to the list your wife just gave you. Yesterday's list was: [tomatoes, onions, ketchup] Combined with [eggs, carrots, hamburger, fleacollar] we obtain [eggs,carrots,hamburger,fleacollar,tomatoes,onions,garlic]. To take one list and to attach it to the tail of another list is to "append" the first to the second. The PROLOG definition of append is: Rule1: append( [], L, L ). Rule2: append( [X|List1], List2, [X|List3] ) :- append( List1, List2, List3 ]. The general scheme is this: The definition consists of one rule and one fact. The rule will be used over and over again until what little is left matches the fact. The [] stands for empty list, which is like a bag without anything in it. This is an example of a recursive definition. Suppose we ask: append( [a,b,c], [d,e,f], Whatgives ). 1. Rule 2 is invoked with arguments ( [a,b,c], [d,e,f], Whatgives ). 2. Rule 2 is invoked again with arguments: ( [b,c], [d,e,f], List3 ). 3. Rule 2 is invoked again with arguments: ( [b], [d,e,f], List3 ). 4. The arguments are now ([], [d,e,f], List3 ). Rule 1 now matches. End. How does this cause a list to be constructed? The key is to watch the third argument. Supplied by the user, it is named "Whatgives". The inference engine matches it to [X|List3] in rule 2. Now lets trace this as rule two is successivly invoked: Whatgives | | | v Rule2: [X|List3] (List3 = [b,c]) | \ | \ | \ v \ Rule2: a [X'|List3'] (List3' = [c]) | \ | \ | \ v \ Rule2: b [X''|List3''] (List3'' = [], ie., empty set.) | \ | \ | \ Rule1: c L ( in Rule1 = [d,e,f] ) End. L in rule 1 is [d,e,f] for the following reason: Notice that rule 2 never alters List2. It supplies it to whatever rule it invokes. So L in rule 1 is the original List2, or [a,b,c]. This example would not have worked if the order of rules one and two were reversed. The PROLOG inference engine always attempts to use the the first rule encountered. You could imagine it as always reading your program from the top down in attempting to find an appropriate rule. Since rule 2 would always satisfy, an unpleasant thing would have happened if the order were reversed. The program would loop forever. I hope that this tiny introduction to PROLOG whets your appetite. You should now purchase the book Programming In Prolog W.F. Clocksin and C.S. Mellish Springer - Verlag Berlin,Heidelberg,New York. 1981,1984 -- || || David Fiore, University of California at Riverside. ============= || Slow mail : 1326 Wheaton Way || Riverside, Ca. 92507 || E-Mail || UseNet : ...!ucdavis!ucrmath!hope!fiore || BITNET : consult@ucrvms Have another day! "...and at warp eight, we're going nowhere mighty fast"