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).