alanf@bruce.OZ (Alan Grant Finlay) (03/29/90)
Prolog in Icon (version 2) -------------------------- Alan Finlay, Monash University. The Prolog interpretor associated with this file is written in Icon for a very simple version of pure Prolog. Cuts, arithmetic, assert and retract are not implemented. There is only one non logical primitive "consult" which is used as if it were a fact with one argument. The argument to consult is used as a file name and the file is consulted for clauses and queries. Negation is implemented as negation by failure. Version two includes list notation. Acceptable Prolog programs consist of a list of clauses and queries, one per line. The clauses are either facts or rules: predicate. predicate:-predicate,...,predicate. A fact is a predicate followed by a full stop. The syntax of a predicate will be described later. A rule has a "head" on the left of the turnstile ":-", and a "body" on the right. The body is a list of one or more predicates separated by commas and terminated by a full stop. The predicates are simple identifiers, identifiers parameterised by one or more arguments, or negated predicates: identifier identifier(argument,...,argument) ~predicate An identifier is a string of letters, digits, underline or full stop. An identifier which starts with an upper case letter and has no arguments associated with it is interpreted as a variable identifier. The arguments are syntactically identical to predicates but interpreted differently. Those arguments with arguments of their own are called structures, those without are called constants if not starting with an upper case letter and variables if they do. A query is like a rule without a head: :-predicate,...,predicate. ?-predicate,...,predicate. The first form causes the interpreter to find all solutions to the query. The second form only asks for one solution. The interpreter reports values assigned to free variables in the query and this is the way answers to questions more complex than yes/no are obtained. As a simple example here is a traditional inference test program mortal(X):-man(X). man(X):-greek(X). greek(socrates). ?-mortal(socrates). Try typing in this example after starting the interpreter with the command iconx prolog and the response is yes After this the interpreter will be waiting for another clause or query to be entered. Try entering another query for example ?-mortal(Socrates). which produces the strange response yes, Socrates = socrates This is because the upper case S indicates a free variable. To experiment with negation try being(X):-man(X). being(X):-god(X). god(apollo). :-being(X),~mortal(X). which produces the response yes, X = apollo no more solutions Note that negation should only be applied to ground terms (terms with all the variables bound) or strange behaviour may result. For example the query :-~mortal(X),being(X). which fails with no solutions. Finaly send an end of file to finish interpreting Prolog commands. More examples can be found in files "test1.plg", "test2.plg", . . . To run the first of these enter the fact consult(test?.plg). etc, after starting the interpreter. The list notation is simply a set of convenient abbreviations. Lists are assumed to be represented by using the binary dot constructor "." and "nil". The dot constructor should only be applied to (element,list) pairs and "nil" represents an empty list. An infix version of the dot constructor "|" is also provided and is useful for pattern matching. Some examples follow. abbreviation represents [] nil [1] .(1,nil) 1|nil .(1,nil) [1,2] .(1,.(2,nil)) [1,2,3,4] .(1,.(2,.(3,.(4,nil)))) 1|2|3|4|nil .(1,.(2,.(3,.(4,nil)))) [[1,2],[3,4]] .(.(1,.(2,nil)),.(.(3,.(4,nil)),nil)) 1|2 .(1,2) The last example is not a proper list since the second argument of the dot constuctor is not a list. The list [A,B,C,D] must have exactly four elements whereas the list A|B|C|D has three or more depending upon the length of the list bound to D. The following two versions of naive reverse are exactly equivalent. reverse([],[]). reverse(X|Y,Z):-reverse(Y,W),append(W,[X],Z). append(X,[],X). append([],X,X). append(X|Y,Z,X|W):-append(Y,Z,W). reverse(nil,nil). reverse(.(X,Y),Z):-reverse(Y,W),append(W,.(X,nil),Z). append(X,nil,X). append(nil,X,X). append(.(X,Y),Z,.(X,W)):-append(Y,Z,W).