[comp.lang.prolog] PROLOG DIGEST V6 #28

restivo@POLYA.STANFORD.EDU (Chuck Restivo) (05/10/88)

Date: Thursday, 5 May 1988 0:1:43-PST
>From: Chuck Restivo (The Moderator) <PROLOG-REQUEST@POLYA.STANFORD.EDU>
Reply-to: PROLOG@POLYA.STANFORD.EDU>
US-Mail: P.O. Box 4584, Stanford CA  94305
Subject: PROLOG Digest   V6 #28
To: PROLOG@POLYA.STANFORD.EDU


PROLOG Digest           Friday, 1 Apr 1988      Volume 6 : Issue 28

Today's Topics:
     				Query - Parallel Compilers,     				
		     Implementation - end_of_file & Strings & Eliza
----------------------------------------------------------------------------------------------------------------------------

Date: 23 Mar 88 14:26:19 GMT
>From: mcvax!dutrun!dutesta!ignacio@uunet.uu.net  (Ignacio GARCIA ALVES)
Subject: Parallel prolog compilers and interpreters

We are interested in PARALLEL PROLOG COMPILERS AND INTERPRETERS, like for 
example PARLOG and CONCURRENT PROLOG.

But now the problem: WHERE CAN WE FIND THEM?

So we would like to hear the answers to the following questions:
- where can we order them?
- what are the prices?
- who has already such a compiler or interpreter to hear their experience?
- what are the hardware and software requirements?

We do have the following hardware:
- VAX, Berkeley Unix 4.1
- RT, AIX
- PC

All information is welcome either by post or email!

POST:   Ignacio GARCIA ALVES & Mark KORSLOOT
        Delft University of Technology
        Faculty of Electrical Engineering
        Section Computer Architecture
        Mekelweg 4
        2628 CD  DELFT
        THE NETHERLANDS

EMAIL:  !mcvax!dutrun!dutesta!ignacio.uucp
    or  !mcvax!dutrun!dutesta!mark.uucp

-----------------------------

Date: 24 Mar 88 03:06:23 GMT
>From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  behavior of read/get0 at end_of_file

I just grepped through the UNIX [UNIX is a trademark of AT&T] manuals,
and all I could find was the function feof(Stream).  None of the UNIX 
utilities I am familiar with uses "eof" to signify end of file.
Franz Lisp does something interesting:
	(ratom [Port [Eof]])
	(read  [Port [Eof]])
	(readc [Port [Eof]])
return the Eof argument (which defaults to nil) when you read the
end of the file, so you can get whatever takes your fancy.

> so i think we could maybe abandon the end_of_file notation of Quintus (sorry
> for you Richard, a compatibility switch could very easily turn it back anyway),

But it ***ISN'T*** a Quintus notation!  This is the notation used by
	DEC-10 Prolog
	EMAS Prolog
	C Prolog
	Quintus Prolog
	Stony Brook Prolog
	ALS Prolog
	Expert Systems International Prolog-2
	AAIS Prolog (in "Edinburgh" mode only)
and doubtless many others.  end_of_file IS the "de facto" standard.
Poterie's suggestions are good ones, but in order to overthrow the
de facto standard, they would have to be MUCH MUCH better, and they
aren't.

> but it is not an important point as the aim would be to discipline one's
> programming style by systematically using the test form: 
> 	eof(Term) 
> and never ever explicit the EOF term itself. Portability is great.

Beware.  While Quintus Prolog offers the library predicate
	is_endfile(?EndMarker)
there are other Prolog systems, such as AAIS Prolog, where there is a
predicate with a similar name which takes a Stream argument:
	is_eof(+Stream)
in AAIS Prolog means "is it the case that Stream is positioned at its end?".
Yes, portability is great, but would it not be more just to reward those
people (such as SICS, Saumya Debray, ALS, and others) who have tried to
provide it, by standardising their solution?

> As a side effect, close/1 is
> not strictly necessary anymore as the following sequence does the job:
> 		eof(EOF), put(EOF)
Um, what about INPUT streams?  And there is another reason for wanting
close/1:  it will close a stream which is not the current output stream.

------------------------------

Date: 26 Mar 88 05:25:23 GMT
>From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  End-of-file handling

In article <2403@zyx.UUCP>, bd@zyx.UUCP (Bjorn Danielsson) writes:
> I can't understand why there should be a "strait-jacket solution" to this
> kind of problem. Why not put in enough flexibility to allow for the most
> obvious cases? In Z-Prolog, (which was never designed to be Edinburgh
> compatible) the "read" predicate can handle end-of-file in three different
> ways, depending on an optional argument:
> 	(1) signal an error,
> 	(2) fail,
> 	(3) return a value supplied by the programmer.
> 
Oh, __HOW__ I wish you were were handling the I/O part of BSI substandard!
That's EXACTLY the right sort of attitude for a standard designer.

I think that there are sound technical reasons for regarding fail-at-end
as a straight-out blunder, and I have used PL/I and Fortran enough to
convince me that end-of-file is NOT an error and shouldn't be treated
like one.  (Reading *past* end-of-file is another matter, which is one of
the things I have against fail-at-end.)  But a more powerful operation,
which is not perceptibly harder to implement, which will let me synthesise
the operation I want, and let BIM synthesize the operation they want,
that's exactly the right thing to do in the standard.

Oddly enough, I had intended to mention Algol 68.  Files in Algol 68 are
rather interesting.  One of the things you can do is say

	FILE example file;
	...
	logical file ended OF example file :=
	    (FILE file parameter) BOOL: (
		# return FALSE to get default action (e.g. error report) #
		# return TRUE to say "corrected, please try again" #
		# or jump out #
	    );

Interlisp does the same sort of thing:

	(WHENCLOSE file 'EOF (FUNCTION (LAMBDA (file) (* action *)) ))

So even if we decide to feed this goose instead of killing it, there are
at least three options:
   1.	specify in each call what action to take on end of file
	read(Stream, Term, EofAction)
	-- This affects 'read' only.

   2.	specify per stream what action to take on end of file
	eof_action(Stream, EofAction)
	-- This could affect any form of input.

   3.	allow both.

One of the constraints which is of interest to Quintus is that whatever the
end of file action is, it has to make sense if the stream was being used by
C or Lisp code.  The nice thing about sticking with -1 as the character
end-of-file mark and adopting option 3 is that it does this.

Note though that as I mentioned in my previous message, just because the
host operating system indicates an end-of-file condition doesn't mean that
it isn't possible to read any more from the file.  (UNIX fans will know
about 'tail -f' and why it is useful...)  The standard should, I said in
'84, include a predicate for testing whether the stream is really ended.
If the stream is not really ended, it should be possible to resume reading.

------------------------------

Date: 22 Mar 88 16:55:39 GMT
>From: mcvax!unido!ecrcvax!bruno@uunet.uu.net  (Bruno Poterie)
Subject:  behavior of read/get0 at end_of_file

I do not think that having read/1 returning an atom on EOF is a bad thing.
If you take as an example certain UN*X tools, they read their input from
a file (typically stdin) until finding a line composed of a single dot.
So it is perfectly legal to submit a file which contains a dot-line in the
middle if you want only the first part to be feeded to the tool. Same thing
for Prolog, if you have a huge file full of various facts but want only say
the first 100 to be used as input in your test program, then simply add
the EOF mark before line 101. I would then prefer to have it as a directive:
		...
		:- eof.

so that it is not a bare fact but actually a command to the consulting tool
that it have to EOF this input source. It is then coherent with other
directives like:
		...
		:- [file3,file4].
		...
which actually order the consulting tool to insert at this point the content
of the named files. I believe that the notation "eof" is quite standard in
the UN*X system and already in some Prolog, including as a test predicate for
this very term:
		... read(Term), eof(Term) -> ...

so i think we could maybe abandon the end_of_file notation of Quintus (sorry
for you Richard, a compatibility switch could very easily turn it back anyway),
but it is not an important point as the aim would be to discipline one's
programming style by systematically using the test form: 
	eof(Term) 
and never ever explicit the EOF term itself. Portability is great.

	Now for the get0/1 [or get_char/1/2]: having it returning an otherwise
impossible value, say an atom as suggested by Micha, is ok if the returned
thing is an integer representing the ascii code [or ebcdic] of the character.
using the same term as the one returned by read/1, and consequently the same
test predicate as only mechanism to check for EOF, would greatly improve the
compactness and consistency of the i/o system. As a side effect, close/1 is
not strictly necessary anymore as the following sequence does the job:
		eof(EOF), put(EOF)
Because obviously put/1 must handle the same term in the same way (I am afraid
that outputing CHAR modulo 256 would not work in this case).
I nevertheless believe that EOF == -1 is a clearer convention, returning an
object of the same type but out of the normal range of normal input, and
is already the UN*X convention. It would not force put/1 to accept it as EOF
character, as it would be outputed as: -1 modulo 256 (or 512) == 255. Passing
-1 to UN*X putchar() does not generate an EOF!

Ok, enough delirium tremens for today. My main point is: the character i/o
should provide a very low level facility, with no hypothesis about the use
which could be made of them. Using read(Term) and eof(Term) provides an
uniform, simple, elegant and portable mean of performing i/o at Prolog term
level. Using get0/1 implies you are interested in the real bits contained
in your input support, so you want to control it at a low level. Returning
the -1 value is portable and low-level, because independant of ascii or
any other character set. Alternatively, returning eof and using the same
eof(Char) test predicate would be again low-level, portable, and free of
any supposed semantic. More important, most of prolog input loops may be
adapted with this scheme at low cost. Failing at EOF, however, would mean
full rewriting of those applications and system libraries.

------------------------------

Date: 22 Mar 88 10:29:39 GMT
>From: mcvax!prlb2!kulcs!bimandre@uunet.uu.net  (Andre Marien)
Subject: end_of_file treatment in prolog

Sorry for being inaccurate: we should have taken the trouble of explaining what
BIMprolog's predicate eof/0 does and it is different from what Richard's
at_eof/0 does:
eof/0 succeeds only after a read/1 or get0/1 has failed because end of
file was encountered
so, let me change buggy_read into:

        non_buggy_read(Term) :- bim_read(Term), ! .
        non_buggy_read(end_of_file) :- eof .

actually, eof/0 is written using a predicate in_status/1 which unifies
its argument with an integer indicating the 'status' of the input stream

> end-failure approach, despite having asked Bart Demoen at the Prolog
> Benchmarking Workshop for enlightenment on this point.  Again, this

Perhaps you asked Andre' Marien, but not Bart Demoen: he was not at the Prolog
Benchmarking Workshop

Now about the transformation of

        s1: a -> s2.
        s1: b -> s1.
        s1: $  -> accept.

to a prolog procedure;

1. the textbook uses an explicit end of file marker, so it is clear that the
   behavior of Cprolog's get0/1 suites better in this transformation;
   still, I would rather represent a state by a predicate with arity 0 and let
   it get its character itself:
   
        s1 :- get0(X) ,
        	(X = a , s2 ;
        	 X = b , s1 ;
        	 X = -1 , true
        	) .

      this of course with get0/1 behaving like in Cprolog

2. Now, do it with BIMprolog's get0/1, I will call it BIMget0 so that you will
   always know which behavior to expect

   s1 :- BIMget0(X) , (X = a , s2 ;
        	       X = b , s1
        	      ) .
   s1 :- eof .
   
   this doesn't look very nice, but
   
	a. I would expect that in a parser, in most states eof indicates an
	   error, so that error recovery must be done, which is very easy
	   (in prolog) by backtracking to the appropriate level (state) in the
	   parser; so in most states, there would be no clause like s1 :- eof.
	   then, on eof, s1 fails as it does on input characters different
	   from a or b

	   see Pascal : an endpoint is the endmarker, and occurrence of eof
	                    during tokenizing means an error
	   see Prolog : every clause must have an endpoint; eof could only
	                    occur after a clause

	b. prolog (at least BIMprolog) is used for other things than writing
	   tokenizers - actually, tokenizers should not be written at all: they
	   should be generated - and in an administrative application written in
	   prolog, using BIMread or BIMget, the programmer can feel at ease:
	   after a successful BIMread or BIMget, he has got data; it is in a
	   way impossible for him to forget testing for eof, because otherwise
	   the execution of the program would never have gone so far

3. A more general approach can be used, using a state transition table.
   The previous program can be derived from this by partial evaluation.
   In the triangle puzzle problem discussion, R.O'K argued that this
   approach is more general.

	step_state(accept) :- ! .
	step_state(From) :- BIMget0(X), !,
			From : X => New,
			step_state(New) .
	step_state(From) :- BIMeof,
			From : '$' => New,
			step_state(New) .

	s1: a => s2.
	s1: b => s1.
	s1: '$' => accept.

	If eof is to be treated as an error, remove the last clause of
	step_state/1.
	Eof is handled in one place, in Cprolog one should add :

		transit(si,-1,error) .

	for all states, or write :

		state(From) :-	get0(X), noteof(X), !,
				transit(From,X,New),
				state(New) .

		noteof(-1) :- !, fail .
		noteof(_) .
 
To sum up: there is an appropriate level of testing for eof: BIMread and BIMget
(and BSIread and BSIget for that matter, to answer one of Richard's questions
and worries) allow you to do this testing of eof at these levels only, while
read and get0 of Cprolog force you to test it after every input operation

------------------------------

Date: 23 Mar 88 09:54:10 GMT
>From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  behavior of read/get0 at end_of_file

In article <518@ecrcvax.UUCP>, micha@ecrcvax.UUCP (Micha Meier) writes:
> 	By the way, get0/1 does *not* exist in BSI, it uses get_char/1 instead,
> 	and its argument is a character, i.e. a string of length 1.
> 	This means that the type 'character' is inferred from
> 	the type 'string' (and not the other way round like in C).
> 	Does anybody out there know what advantages this can bring?
> 	It is independent on the character <-> integer encoding,
> 	but this only because explicit conversion predicates have
> 	to be called all the time.

I find it extremely odd to call a string of length one a character.
It's like calling a list of integers which contains one element an
integer.  Do we call an array with one element a scalar?

I haven't commented on the BSI's get_char/1 before because for once they
have given a new operation a new name.  There are two problems with it.
A minor problem is that the result being a string, they can't represent
end of file with an additional character, so the fail-at-end approach is
hard to avoid.  (Not impossible.)  There is an efficiency problem:
something which returns an integer or a character constant can just
return a single tagged item, but something which returns a string either
has to construct a new string every time, or else cache the strings somehow.

For example, Interlisp has a function which returns you the next character
in the current input stream, represented as an atom with one character in
its name.  (Well, almost:  characters `0`..`9` are represented by integers
0..9.)  This was quite attractive on a DEC-20, where you could just compute
a table of 128 atoms once and for all.  It wasn't too bad on VAXen either,
where the table had to have 256 elements.  But it because rather more
clumsy on the D machines, which have a 16-bit character set.  (Can you say
"Kanji"?  I knew you could.)  So the alternatives I can see at the moment
are
    o	construct a new string every time.
    o	precompute 2^16 strings.
    o	cache 2^8 strings, and construct a new string every
	time for Kanji and other non-Latin alphabets.
    o	not support Kanji or other non-Latin alphabets at all.
(Can you say "Cyrillic"?  How about "Devanagari"?  You may need the
assistance of a good dictionary; I used to mispronounce "Devanagari",
and probably still do.)

I wrote that
> >For example, the arcs
> >	s1: a -> s2.
> >	s1: b -> s1.
> >	s1: $  -> accept.
> >would be coded like this:
> >	s1(0'a) :- get0(Next), s2(Next).
> >	s1(0'b) :- get0(Next), s1(Next).
> >	s1(- 1) :- true.
Meier says that
> 	In his tutorial to the SLP '87 Richard has taken another
> 	representation of a finite automaton which is more appropriate:
> 	s1 :-
> 		get0(Char),
> 		s1(Char).
> 
> 	s1(0'a) :-
> 		s2.
> 	s1(0'b) :-
> 		s1.
> 	s1(-1) :-
> 		accept.
There wasn't time to go into this in detail in the tutorial, but it
should be obvious that the first approach is more general:  in particular
it can handle transitions where (perhaps because of context) no input is
consumed, and it can handle lookahead.
>	Such representation can
> 	be more easily converted to the BSI's variant of get:
> 	s1 :-
> 		% do the corresponding action
> 		( get0(Char) -> s1(Char)
> 		;
> 		  accept
> 		).
This doesn't generalise as well as the end-marker version.
Here is the kind of thing one is constantly doing:

	rest_identifier(Char, [Char|Chars], After) :-
		is_csymf(Char),
		!,
		get0(Next),
		rest_identifier(Next, Chars, After).
	rest_identifier(After, [], After).

See how this code can treat the end marker just like any other
character:  because it doesn't pass the is_csymf/1 test (copied from
Harbison & Steele, by the way) we'll pick the second clause, and there
is no special case needed for an identifier which happens to be at the
end of a stream.

The fail-at-end approach forces us not only to do something special
with the get0/1 in rest_identifier/3, but in everything that calls it.
(In the Prolog tokeniser, there are two such callers.)

The point is that if-then-elses such as Meier suggests start
appearing all over the place like maggots in a corpse if you adopt
the fail-at-end approach, to the point of obscuring the underlying
automaton.

> 	I must say, none of the two seems to me satisfactory. Richard's
> 	version is not portable due to the -1 as eof character.

If the standard were to rule that -1 was the end of file character,
it would be precisely as portable as anything else in the standard!
In strict point of fact, the Prolog-in-Prolog tokeniser was written
in DEC-10 Prolog for DEC-10 Prolog, and used 26 as the end of file
character, and 31 as the end of line character.  It took 5 minutes
with an editor to adapt it to Quintus Prolog.  I wish C programs
written for UNIX took this little effort to port!

> 	for a Prolog system it is better to have get0/1 return
> 	some *portable* eof (e.g the atom end_of_file, for get0/1
> 	there can be no confusion with source items) instead of
> 	some integer.

It is important that the end-of-file marker, whatever it is, should be
the same kind of thing, in some sense, as the normal values, so that
classification tests such as is_lower/1, is_digit/1, and so on will
just fail quietly for the end-of-file marker, not report errors.  Since
end of file is rare, we would like to test the other cases first.
Pop-2 on the Dec-10 returned integers almost all the time, except that
at the end of a stream you got an end-of-file object which belonged to
another data type (there was only one element of that data type, and it
printed as ^Z).  This was in practice a major nuisance, because before
you could do anything other than an equality test with the result, you
had to check whether it was the end of file mark.

I have been giving out copies of the Prolog-in-Prolog tokeniser to show
how easy it is to program character input with the Edinburgh Prolog
approach.  If someone would give me a tokeniser for BSI Prolog written
entirely in BSI Prolog using the fail-at-end approach, and if that
tokeniser were about as readable as the Prolog-in-Prolog one, that would
go a long way towards convincing me that fail-at-end was a good idea.

> 	BSI objects that if [read/1] returns e.g. the atom end_of_file
> 	then any occurrence of this atom in the source file
> 	could not be distinguished from a real end of file.

That's not a bug, it's a feature!  I'm serious about that.  At Edinburgh,
I had the problem that if someone asked me for help with Prolog, they
might be using one of four different operating systems, where the end
of file key might be
	^Z
or	^D
or	^Y
or	something else which I have been glad to forget.
No problem.  I could always type
	end_of_file.
to a Prolog listener, and it would go away.  Oh, this was so nice!
In fact, on my SUN right now I have function key F5 bound to
"end_of_file.\n" so that I can get out of Prolog without running the
risk of typing too many of them and logging out.

Another thing it is useful for is leaving test data in a source file.
One can do
	<declarations>
	<clauses>
	end_of_file.
	<test cases>
and include the test cases in the program or not just by moving the
end_of_file around.

Ah, you'll say, but that's what nested comments are for!
Well no, they don't work.  That's right, "#| ... |#" is NOT a reliable
way of commenting code out in Common Lisp, and "/* ... */" is NOT a
reliable way of commenting code out in PopLog.  But end_of_file, in
Edinburgh Prolog, IS a reliable way of commenting out the rest of the file.

> 	In this case, a remedy would be the introduction of

Prolog needs a remedy for end_of_file like Elizabeth Schwarzkopf
needs a remedy for her voice.

Before taking end_of_file away from me, the BSI committee should supply
me with a portable way of exiting a break level and a reliable method of
leaving test cases in a file without having them always read.

------------------------------

Date: 24 Mar 88 08:58:35 GMT
>From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject: behavior of read/get0 at end_of_file

Just to continue with the get0 topic:

	The fail-at-end approach rests on an assumption
	which deserves to be made explicit, because it is false.

What is the assumption?   That receiving the end-of-file indication from
an operating system indicates that there is nothing further to read in
that stream.  This is false?  Yes.

Let's ignore 4.2BSD sockets, V.3 Streams, non-blocking I/O, VMS
concatenated files, and other esoterica which one doesn't expect
BSI Prolog to cope with.  Let's just consider terminals.

In Tops-10 (home of DEC-10 Prolog):
	end-of-file from the terminal is a software convention (^Z).
	You can just keep reading from the terminal after that, and
	in fact that's exactly what DEC-10 Prolog does.

In UNIX (original home of C Prolog):
	end-of-file from the terminal is a software convention
	(EOF character typed after an empty line).
	You can just keep reading from the terminal after that, and
	in fact that's exactly what C Prolog does.

In VM/CMS, using SAS Lattice C
	end-of-file from the terminal is a software convention
	(some magic string, which defaults to "EOF", but it is
	trivially easy for a program to change it -- use afreopen()).
	I believe that you can keep reading from the terminal after
	that, but I haven't tried it myself.

On a Macintosh, using ALS Prolog
	end-of-file from a window is a software convention
	(you click on "End of File" in the "Edit" menu).
	All windows and streams remain live after that, and
	you can just keep reading, and that's what ALS Prolog does.

On a Xerox Lisp Machine, using Xerox Quintus Prolog
	end-of-file from a TEXEC window is a software convention.
	All windows and streams remain live after that, and
	you can just keep reading, and that's what XQP does.

[The sample of Prologs is not of interest here; my point is that there
 are several *operating systems* with this characteristic.
]
So the rule actually followed in Edinburgh-compatible Prologs is that
    -   the sequence of characters codes returned by get0/1 is
	the sequence of characters delivered by the source
    -   with the end-of-file marker inserted every time the
	host indicated the end-of-file condition
    -	Prolog receives through get0/1 as many characters and as many
	end-of-file markers as there are; any attempt to read past the
	end of this union stream is an error.  Not a failure, an error.

It happens that when you are reading from disc files, most operating
systems will indicate the end of file condition once.

Are terminals the only kind of file for which multiple end-of-file
conditions are plausible?  No.  The convention for tapes is that a
single tape-mark (usually reported as an end-of-file condition) is
merely a separator; a tape as such is terminated by a double tape-mark.
Thus a Prolog program copying one tape to another (this is a reason why
we might want put(-1) NOT to close a file; if it does anything special
on a tape it should be to write a tape-mark) might want to keep reading
after seeing an end-marker.

------------------------------

Date: 24 Mar 88 15:29:47 GMT
>From: mcvax!ukc!dcl-cs!simon@uunet.uu.net  (Simon Brooke)
Subject:  Strings

In article <776@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>Xerox Lisp uses lists for bignums to this very day.

Yes, true. But please don't assume this means it is efficient. For
example, I recently benchmarked a Xerox 1186 running Interlisp (Koto)
against the new Acorn Archimedes running Arthur Norman's Cambridge Lisp.
Generally the Arch was a bit faster, reflecting the simpler lisp and
faster processor. But running (fact 1000) it was 321 (three hundred and
twenty one) times faster - and this must reflect grotesque inefficiency in
Xerox' bignum code.

------------------------------

Date: 24 Mar 88 18:35:05 GMT
>From: eagle!icdoc!doc.ic.ac.uk!cdsm@ucbvax.Berkeley.EDU  (Chris Moss)
Subject:  Strings

I haven't contributed to the string discussion because I don't believe I
know all the answers. But I do have strong reservations about the current
Edinburgh implementations. Let me air them:

1. They don't get printed properly by "write". I don't like seeing
"Prolog" come out as [80,114,111,108,111,103]. OK, I can define a
"writestring", but not use it within a bigger structure without pain.  

Now here's an odd thing: there is no writestring routine in the Quintus
library that I can discover! Not in the built-ins or the (extensive)
library!  

What does that tell us about the use of strings? It suggests to
me that people actually always use atoms for this purpose, and somewhere 
in their code is an implicit definition: 
    writestring(String) :- name(Atom,String),write(Atom).  

Note that in most systems this involves an entry in the symbol table 
(reasonably slow) and a limit of 256 (or maybe 512) characters.

MuProlog DOES print out "Prolog" as a string, wherever it occurs.
Presumably it has to scan the list first. It uses list format whenever
there is a integer outside the range 32-127 in the list (it also gets tabs
right tho I don't understand why it finishes at 127 not 126). That's a
pretty good heuristic, tho I can imagine it going wrong on occasions. e.g.
if I read in a clause over several lines the string will contain newlines,
so my DCG debugging will still look horrid!

2. I don't like having ASCII values in my programs. With a certain amount
of discipline and inefficiency one can get round that, by saying, for 
instance:
    lowercase(X) :- "a"=[A], "z"=[Z], X>=A, X=<Z.
but it's not an ideal solution (tho close to normal arithmetic habits in
Prolog). These type of routines tend to be efficiency sensitive. 

OK, there is the 0'a notation (another way of writing 97 if you're using
ASCII). Now that DOESN'T work in MuProlog, or Poplog or ...

On efficiency I mostly agree with Richard. I too like strings to be lists,
and can't see the real benefits of a string type, though you don't tend to
miss what you never had!

So, what I would like to see is not a string type but a CHARACTER type. 
Small integers work in Ed-Prolog mainly because they're efficient for get
and put -- there's no symbol table lookup. It would be nice to treat
single character atoms as their ASCII value, but that's wrong because one
does want to hang things off atoms. So they would have to be a separate
data type. As far as notation is concerned I have no better suggestion
than 0'a tho I don't much like it.

Now I don't object to Pascal's ORD (tho Modula II's ORD is TERRIBLE.
It is defined as CARDINAL so one usually has to say VAL(INTEGER,ORD("a"))).
But one-way transfers aren't much of a problem semantically, so I
wouldn't object to the C solution, which allows them to be used in arithmetic
contexts. e.g. Num is Ch-0'0 or Letter =<0'z.

Thus the main difference with the present systems would be:
  1. 0'a wouldn't unify with 97. (I assume)
  2. write(0'a) would print out 0'a.
  3. write("abc") or write([0'a,0'b,0'c])  would print out as "abc".
  4. One would need a "CHR" function (but not ORD) in arithmetic
expressions.

The question is, "is it worth the change"?  For my pennyworth the answer
is "yes". NOT having a character type makes Prolog as archaic as Fortran
IV in computer-science terms. I don't much like the string type idea. And
if you say "you proposed it" you're wrong. I've only been concerned with
syntax and semantics, not the built-in-predicates (there are limits to the
number of committees any sane person can attend!). Strings have been mostly
discussed in the BIPs meetings. Most of my suggestions at main committee
meetings have been ignored! When it comes to the semantics one needs a
character type even in the present proposal.

The biggest anti-argument is that all sorts of Prolog programs might break
in weird ways because of difference 1. I don't know the answer to that.

-- Chris Moss
 
------------------------------

Date: 21 Mar 88 08:45:07 GMT
>From: otter!kers@hplabs.hp.com  (Christopher Dollin)
Subject:  Prolog implementations in Lisp

Pop11 is like Lisp[*3] in that it has dynamic typing, dynamic store allocation
with garbage collection, first class (really, *1st*, not 1.5st) procedures,
lexical scoping, and run-time access to the compiler. It is unlike Lisp in that
it has a concrete syntax, open stack, partial application, user-defined
datatypes that aren't just funny uses of vectors or lists, and coroutines.

I think I'll go and lie down. Notefeet follow.

[*1] Systems Designers market Poplog in the USA and UK for commercial clients.
     Sussex University deal with educational establishments in the UK, and
     Robin Popplestone does so in the USA.

[*2] OK, quite a lot really.

[*3] When I say Lisp I mean Vulgar - sorry, Common - Lisp.

Regards,
-- Kers              

-------------------------------
                   
Date: 25 Mar 88 04:39:20 GMT
>From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject: My views on developing a PROLOG standard

In article <240@gould.doc.ic.ac.uk>, cdsm@ivax.doc.ic.ac.uk (Chris Moss) writes:
> Richard's certainty that the
> Prolog world begins and ends with Edinburgh is not shared in France!

I have no such certainty.  I think the Prolog world includes Israel,
Japan, Australia, Portugal, the USA, Hungary, China[*], and all sorts of
places.  The plain fact of the matter is that there are two sorts of
Prolog systems:  ones whose authors have tried to provide some sort of
compatibility with other Prologs, and ones whose authors have let their
imaginations rip.  What the compatible Prologs are compatible with is
not Prolog-II or Waterloo Prolog, but Clocksin&Mellish.

[*] I am credibly informed that the PRC uses an unauthorised translation
    of Clocksin & Mellish as the main Prolog text, so presumably the
    French Prologs are of small concern to them.

------------------------------

Date: 20 Mar 88 20:47:39 GMT
>From: lagache@violet.Berkeley.EDU  (Edouard Lagache)
Subject: An Eliza-like problem solving assistant (400+ lines).

    The following program is the mockup of the Eliza-like problem solving
    assistant that was demonstrated at the March 10 meeting of the PROLOG Forum.
    The program is the result of 3 late night work, and NO claims of
    correctness or efficiency are expressed on implied.  On the contrary,
    suggestions for expansion or improvement are most welcome.  As stated
    earlier, it is hoped to turn this program into a group project, so
    we hope that there is plenty of room for expansion!

    There are some calls to my imfamous PROLOG libraries.  The 'window'
    and 'set_attribute' calls will only work on a Texas Instruments PC,
    so I leave it to you to omit, or port these calls to your system.
    There is one call to the predicate 'nthelem', I have enclosed a copy
    of the predicate at the end of the file.  There may be other calls
    that I have forgotten, if so let me know and I will provide the needed
    code.

    Hack to your hearts delight!

    -- Edouard Lagache

/* File: 'consulta.pro' */
/******************************************************************************/
/*                                                                            */
/*                  An A.I. Consultant for PROLOG Programmers                 */
/*                                                                            */
/*       This program is intended to serve as a "intelligent consultant"      */
/*  for PROLOG programs to turn to when encountering some impasse in a        */
/*  programming project.  The program is based on the "Eliza" program, but    */
/*  it designed to provide comments that might foster the user to "solve"     */
/*  his/her own problem.                                                      */
/*                                                                            */
/*               A collaborative project of the PROLOG Forum.                 */
/*    Release - 1.00,  March - 1988,  Copyright(C) 1988, The PROLOG Forum     */
/*                                                                            */
/*  Credits: The concept of an "Eliza" type program to help users with        */
/*           problem solving was first proposed (as far as we know) by        */
/*           Professor Charles Woodson of the School of Education at          */
/*           U.C. Berkeley.  He also built a small system in LISP for the     */
/*           purposes of demonstrating the concept to members of his LISP     */
/*           programming course.                                              */
/*                                                                            */
/******************************************************************************/

/*>> 'gethelp' is the routine that the user can call to get access to the <<*/
/*>> system.  E. Lagache, Ver-1.0, 3/88                                   <<*/
gethelp :- tell('_WINDOWS'), make_window(0,15,14,64), set_attribute(magenta),
           clear_screen, set_attribute(white),
           prtstr("Please describe your problem, type 'quit.' to resume work"),
           nl, converse, close_window, tell(user).

/*>> 'converse' is the main "looping" routine.  It takes a list of words <<*/
/*>> and searches for keywords.  Then it generates a response based on   <<*/
/*>> keywords.  The responses are randomized to make the system more     <<*/
/*>> "humanlike".   E.L.,  Ver-1.0, 3/88                                 <<*/
converse :- set_attribute(white), prtstr("<>-> "), set_attribute('yellow'),
            read_sentence(Request), nl, remove_duplicates(Request,Request1),
            make_reply(Request1,Reply), set_attribute(cyan),
            print_reply(Reply), nl, continue(Request1).

/* continue makes the recursive call to 'converse' if the user doesn't want */
/* quit */
continue(['quit','.']) :- set_attribute(white), pause.
continue(_) :- converse.

/* 'pause' uses the interval function to simply carry out some time consuming */
/* task to make a delay between the exit prompt, and the closing of the       */
/* window.                                                                    */
pause :- interval(1,X,10), fail.
pause.

/* 'print_reply' simply prints out the list of items recursively */
print_reply([]).
print_reply([Item|Rest]) :- print(Item), put(32), print_reply(Rest).


/*>>------------------------------------------------------------------------<<*/
/*>> 'make_reply' generates a response to a keyword in the users input text <<*/
/*>> it keeps a list of keywords and appropriate responses, and chooses one <<*/
/*>> randomly to provide a "natural" appearance.                            <<*/
/*>> E. Lagache,  Ver - 1.0, 3/88                                           <<*/
/* Exit comment */
make_reply(['quit','.'],['Thank','you','I','hope','these','comments','were',
                         'useful.']
          ).

/* Main test, select some set of keywords, test if they match, if so succeed */
/* otherwise fail and look at another possibility.                           */
make_reply(Sentence,Reply) :- word_class(Keywords,Responses),
                              intersection(Keywords,Sentence,List),
                              List \== [], !, length(Responses,Top),
                              irandom(1,Top,Number),
                              nthelem(Responses,Number,Reply).

/* if no keywords are found, then use default responses */
make_reply(_,Reply) :- default_responses(Responses), length(Responses,Top),
                       irandom(1,Top,Number), nthelem(Responses,Number,Reply).

/* 'remove_duplicates' returns a list that contains only one of each item.  */
/* This is necessary for the 'intersection' predicate, and makes the search */
/* less time consuming.  E.L. 3/88                                          */
remove_duplicates([],[]).
                             /* First case, don't copy duplicate items */
remove_duplicates([Item|Rest],NewRest) :- member(Item,Rest), !,
                                          remove_duplicates(Rest,NewRest).
                             /* If not duplicated, then copy */
remove_duplicates([Item|Rest],[Item|NewRest]):- remove_duplicates(Rest,NewRest).

/* 'intersection' return true if one of the keywords was found among the */
/* words typed in.  From C&M page 154 */
intersection([],X,[]).
intersection([X|R],Y,[X|Z]) :- member(X,Y), !, intersection(R,Y,Z).
intersection([X|R],Y,Z) :- intersection(R,Y,Z).

/*>> 'irandom' returns a integer in the range specified by the first two <<*/
/*>> arguments to the predicate, E. Lagache, Ver-1.0, 3/88               <<*/
/*>> Values for computation taken from the first edition of "Oh Pascal"  <<*/
/*>> By Clancy and Cooper (page-227).                                    <<*/
irandom(Lower,Upper,Number) :- get_seed(Seed),
                               Start is (25173*Seed + 13849) mod 65536,
                               Number is (Start mod (Upper - Lower)) + Lower.

/* 'get_seed' will in general be an implementation specific predicate.     */
/* For ADA PROLOG, 'get_seed' will return the number of logical inferences */
/* so far made, using the ADA specific 'licount' predicate                 */
get_seed(Seed) :- licount(Seed).



/*>>---------------------------------------------------------------------<<*/
/*>> 'read_sentence' is a routine to take user input and make a list of  <<*/
/*>> atoms out of it.  It is slightly modified from Clocksin & Mellish   <<*/
/*>> page 104.                                                           <<*/
read_sentence([W|Wa]) :- get0(C), readword(C,W,C1), restsent(W,C1,Wa).

/* Given a word and the character after it, read in the rest of the sentence */
restsent(W,_,[]) :- lastword(W),!.

restsent(W,C,[W1|Wa]) :- readword(C,W1,C1), restsent(W1,C1,Wa).

/* Read in a single word, given initial character, and remembering what */
/* character came after that word.                                      */
readword(C,W,C1) :- single_character(C), !, name(W,[C]), get0(C1).

readword(C,W,C2) :- in_word(C,NewC), !, get0(C1), restword(C1,Cs,C2),
                    name(W,[NewC|Cs]).

readword(C,W,C2) :- get0(C1), readword(C1,W,C2).

/* continue process of stringing characters of the same word together */
restword(C,[NewC|Cs],C2) :- in_word(C,NewC), !, get0(C1), restword(C1,Cs,C2).

restword(C,[],C).

/*  These characters form words on their own */
single_character(44).        /* , */
single_character(59).        /* ; */
single_character(58).        /* : */
single_character(63).        /* ? */
single_character(33).        /* ! */
single_character(46).        /* . */

/* These characters can appear within a word */
/* the second in_word clause converts letters to lower case */
in_word(C,C) :- C>96, C<123.                /* 'a' to 'z' */
in_word(C,L) :- C>64, C<91, L is C+32.      /* 'a' to 'z' */
in_word(C,C) :- C>47, C<58.                 /* '0' to '9' */
in_word(39,39).                             /* '\'' */
in_word(45,45).                             /* '-' */

/* These words terminate a sentence */
lastword('.').
lastword('!').
lastword('?').

/*>>-----------------------------------------------------------------------<<*/

/*>> 'word_class' and 'default_responses' contain the text that will be    <<*/
/*>> presented to the user.  'word_class' also contains the list of        <<*/
/*>> keywords, that will be used to decide if this type of response is     <<*/
/*>> appropriate.                                                          <<*/

/* --------------------- Programming specific keywords -------------------- */
/* Words related to failure to get the file to consult properly */
word_class([consult,consulting,compile,compiling,load,loads,loading],
           [
              ['Do',you,know,at,what,location,the,problem,'is?'],
              ['Could',the,problem,be,at,a,different,place,from,where,the,
               error,message,is,'reported?'
              ],
              ['What',sort,of,diagnostic,message,did,the,system,'give?'],
              ['What',sort,of,problems,could,have,caused,this,'situation?'],
              ['Is',there,another,way,you,could,arrange,your,file,that,might,
               make,it,easier,to,find,the,'problem?'],
           ]
          ).

/* Problems with incorrect output */
word_class([output,print,prints,printing,write,writes,writing,printout],
           [
              ['What',sort,of,output,were,you,'expecting?'],
              ['What',kind,of,output,did,you,actually,get,'(if','anything)?'],
              ['How',could,you,modify,your,program,to,get,more,information,
               about,this,'i/o','problem?'
              ],
              ['Can',you,see,where,in,the,program,the,bug,must,be,'located?'],
              ['How',could,you,further,localize,the,source,of,the,incorrect,
               'output?'
              ]
           ]
          ).

/* Input problems */
word_class([input,read,reads,reading],
           [
              ['How',do,you,that,the,problem,is,caused,by,incorrect,input,
               'routines?'
              ],
              ['How',could,you,modify,your,program,to,get,more,information,
               about,this,'i/o','problem?'
              ],
              ['How',could,you,further,localize,the,source,of,the,incorrect,
               input,'behavior?'
              ],
              ['How',could,you,test,these,input,routines,in,'isolation?'],
           ]
          ).

/* flow of control problems */
word_class([infinite,loop,recursion,stepping,trace,tracing],
           [
              ['Where',is,the,last,place,that,you,know,your,program,was,running,
               'correctly?'
              ],
              ['How',do,you,know,that,the,program,is,not,behaving,as,it,
               'should?'
              ],
              ['Which',predicates,could,have,caused,this,'phenomenon?'],
              ['Is',there,any,way,that,you,could,isolate,the,predicates,that,
               are,at,'fault?'
              ],
           ]
         ).
/* Error word */
word_class([error,warning,failure,diagnostics],
           [
              ['Can',you,isolate,the,error,to,one,'place?'],
              ['Can',you,find,a,reasonable,interpretation,for,these,
               diagnostics
              ],
              ['Have',you,encountered,similar,sorts,of,messages,in,the,
               'past?'
              ],
              ['What',sort,of,information,would,allow,you,to,deal,with,this,
               'message?'
              ],
           ]
          ).

/* Logical errors */
word_class([infer,inference,deduce,deduction,entails,entailment],
           [
              ['What',should,have,the,system,'deduced?'],
              ['What',was,the,last,inference,that,you,know,was,'correct?'],
              ['How',do,you,know,that,the,inference,was,in,fact,incorrect,
               '(given',the,systems,actual,'configuration)?'
              ],
              ['What',sort,of,database,condition,could,have,caused,the,
               observed,'deductions?'
              ]
           ]
          ).

/* Bug talk */
word_class([bug,malfunction,wrong,incorrect,incomplete,unexpected],
           [
              ['How',do,you,know,you,have,a,'bug?'],
              ['Where',is,the,last,place,that,you,know,your,program,was,
               functioning,'correctly?'
              ],
              ['What',program,behavior,where,you,'expecting?'],
              ['What',indicates,that,something,is,'wrong?'],
              ['What',occurred,that,was,not,'expected?'],
              ['What',information,would,you,need,to,isolate,the,'bug?'],
              ['what',would,you,need,to,know,to,locate,the,'malfunction?'],
              ['What',tests,could,you,perform,to,get,at,the,'problem?'],
           ]
          ).

/* -----------------  Problem solving keywords  ------------------------- */
/* Alternatives */
word_class([option,options,alternatives,possible,possibilities],
           [
              ['What',alternatives,have,you,already,'tried?'],
              ['Are',there,other,possibilities,that,you,might,'consider?'],
              ['Which',options,have,you,already,'tried?'],
              ['Might','I',suggest,that,you,take,a,new,look,at,your,
               'alternatives.'
              ],
           ]
          ).
/* Reflection, on previous work */
word_class([tried,attempted,thought],
           [
              ['What',have,you,done,in,the,past,in,such,'situations?'],
              ['Tell',me,which,approaches,you,have,already,'tried?'],
              ['What',have,you,attempted,'previously?'],
              ['What',have,you,done,here,that,you,might,want,to,do,differently,
               in,the,'future?'
              ]
           ]
          ).

/* Strategic problem solving, evaluating plans */
word_class([try,attempt,do,complete,investigate,think,thinking],
           [
              ['How',will,trying,this,help,you,out,of,your,'impasse?'],
              ['What',can,you,learn,from,doing,'this?'],
              ['Are',you,sure,that,there,is,not,a,more,productive,investigation,
               that,you,could,'make?'
              ],
              ['Are',there,better,ways,to,get,the,information,you,need,to,solve,
               this,'problem?'
              ],
           ]
          ).

/* -------------------------- Human Psychology words ----------------------- */
/* stuck words */
word_class([stuck,stopped,impasse],
           [
              ['Perhaps',you,should,reflect,back,on,the,various,'possibilities.'
              ],
              ['There',must,be,alternatives,that,you,have,not,'considered.'],
              ['I',suggest,that,you,step,back,from,the,problem,and,review,
               what,you,have,'tried.'
              ],
           ]
          ).
/* "down" words */
word_class([depress,depressing,depressed,frustrating,frustrated,mad,annoy,
            annoyed,annoying
           ],
           [
              ['It',is,not,a,good,idea,to,get,worked,up,about,a,'program.'],
              ['One',should,not,take,this,too,'seriously,',after,all,it,is,
               only,a,'program.'
              ],
              ['If',this,task,is,getting,to,you,perhaps,you,should,take,a,break,
               and,come,back,to,it,'later.'
              ],
              ['Perhaps',you,have,been,working,too,long,on,this,one,'problem,',
               maybe,you,should,take,a,'break.'
              ],
              ['Do',you,tell,me,that,this,program,is,getting,to,'you!'],
              ['Well',nobody,said,that,programming,was,'easy.'],
              ['Do',not,get,worked,up,over,'this,','after,all,',no,program,that,
               is,interesting,is,easy,to,'write.'
              ]
           ]
         ).

/* "Bad" words (should this sort of thing be censored!?!) */
word_class([fuck,fucking,shit,shitty,damn,screw,screwed,hell],
           [
              ['Well','I',hope,that,relieves,your,'aggressions;',now,can,
               we,get,back,to,'work?'
              ],
              ['I',am,glad,you,know,'profanity;',unfortunately,this,system,
               only,understands,'PROLOG!'
              ],
              ['Yes,','yes,',profanity,is,the,language,that,all,programmers,
               know,'best!'
              ],
              ['If',you,can,not,say,anything,more,'constructive,',perhaps,
               you,should,take,a,break,and,come,back,to,this,'problem.'
              ],
              ['Sorry',that,language,is,not,in,my,'vocabulary!'],
           ]
         ).

/*  Help words */
word_class([help,assistance,explain,explanation],
           [
              ['In',what,area,do,you,need,some,'assistance?'],
              ['Can',you,be,more,specific,about,what,sort,of,help,you,'need?'],
              ['Exactly',what,sort,of,information,do,you,'seek?'],
              ['In',what,way,may,'I',be,of,'assistance?'],
              ['What',kind,of,advice,do,you,'need?'],
              ['Exactly',in,what,area,do,you,need,an,'explanation?'],
              ['Please',tell,me,background,about,your,'problem?'],
              ['Could',you,further,elaborate,on,the,type,of,problem,you,are,
               'having? '
              ]
           ]
          ).

default_responses([
                   ['Please','continue.'],
                   ['Could','you','say','more','about','your','problem.'],
                   ['I','would','like','to','hear','some','more','specifics.'],
                   ['Could','you','please','elaborate','on','one','aspect',
                    'of','your','problem.'
                   ],
                   ['Is',there,anything,else,that,you,know,about,this,
                    'problem?'
                   ],
                   ['I',do,not,quite,understand,the,'situation;',could,you,
                    elaborate,it,for,'me?'
                   ]
                  ]
                 ).

/* * * * * * * * * * * * * * * * * * * * * * * */
/*  'nthelem' returns the element in the       */
/*  'Index' place of the list.                 */
/*                                             */
/*     E. Lagache,  Vers. - 1.00, Dec - 86     */
/* * * * * * * * * * * * * * * * * * * * * * * */
nthelem([],_,error):- !, fail.  /* fail if list is smaller than index */
nthelem([Item|_],1,Item):- !.   /* return item */
nthelem([X|Rest],NewIndex,Item):- Index is NewIndex-1,nthelem(Rest,Index,Item).

/* end file consulta.pro */

------------------------------

Date: 24 Mar 88 02:37:00 GMT
>From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  An Eliza-like problem solving assistant (400+ lines).

In article <7845@agate.BERKELEY.EDU>,
lagache@violet.berkeley.edu (Edouard Lagache) distributed
an "Eliza-like problem solving assistant".

(1) In the tables at the end of the program, the pattern
	word_class([...],
	    [
		[...],
		...
		[...],
*--------------------^
	    ]).
    occurs quite often.  While C allows extra commas in initialisers,
    many Prolog systems will be unhappy about that extra comma.

(2) In order to test whether any of a given list of Keywords occurs in
    a given Sentence, the program does

	intersection(Keywords, Sentence, List),
	List \== [],

    This is correct, but there isn't a lot of point in constructing List.
    A more efficient approach (effiency is not a concern in this program)
    would be to call

	intersect(Keywords, Sentence)

    where for example

	intersect(Set1, Set2) :-
		member(X, Set1),
		member(X, Set2),
		!.

(3) I thought I'd try the program.  This is what I got:
Please describe your problem.  Type 'quit.' to resume work.
e> My nematodes have been eaten by the peripatus.
Could you say more about your problem. 
e> Yes.
Could you please elaborate on one aspect of your problem. 
e> Well, the peripatus crawled out of its box last night, and it got into
e> another box on the same bench, where we keep nematodes, and well, it
e> ate the lot of them.
Is there anything else that you know about this problem? 
e> I suppose there are two problems, really.  One problem is how do I
e> stop this sort of thing in the future, and the other is where do I
e> get some more nematodes right now.  I want your help with the second
e> part of the problem.
What can you learn from doing this? 
e> From doing WHAT?
Could you say more about your problem. 
e> I just told you everything there was to say.
Could you say more about your problem. 
e> You're getting a bit repetitious, aren't you?
I do not quite understand the situation; could you elaborate it for me? 
e> Gods below, what is there to understand?  I need some nematodes, I
e> had some nematodes, but Hodgkins' wretched peripatus ate them.
Is there anything else that you know about this problem? 
e> Oh forget it.
Could you say more about your problem. 
e> quit.

    In case you were wondering, the e> lines do make sense.

(4) Part of the reason for the frustrating and unhelpful nature of the
    conversation shown is that the program is not Eliza-like.  One of
    the things that Eliza would do is pick up phrases of yours and
    throw them back at you.  For example, after my third input, an
    Eliza-like program might say
	Tell me more about the box.
    			   ^^^^^^^----- copied from input
    or after the last input but two,
	Why did Hodgkins' wretched peripatus eat them?
		^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ transformed input
------------------------------

End of PROLOG Digest
********************

restivo@POLYA.STANFORD.EDU (Chuck Restivo) (07/04/88)

Date: Wed, 4 May 1988 0:4:41 PST
From: Chuck Restivo (The Moderator) <PROLOG-REQUEST@POLYA.STANFORD.EDU>
Reply-to: PROLOG@POLYA.STANFORD.EDU>
US-Mail: P.O. Box 4584, Stanford CA  94305
Subject: PROLOG Digest   V6 #27
To: PROLOG@POLYA.STANFORD.EDU


PROLOG Digest           Friday, 1 Apr 1988      Volume 6 : Issue 27

Today's Topics:
                 Implementation - Trilogy & Destructive Assignments,
                                  & Simple Problem & end_of_file,
                                          & BSI Standard & A Wager
----------------------------------------------------------------------------------------------------------------------------

Date: 23 Mar 88 19:44:15 GMT
From: pacbell!att-ih!alberta!ubc-cs!voda@AMES.ARC.NASA.GOV  (Paul Voda)
Subject:  Compilation in Trilogy

Here is the answer formulated in a slightly more general setting:

The modes and types of Trilogy permit the native code compilation
of programs in such a way that there are no run-time tags on
most of the values, neither there are any reference counters.

The decision when to copy out and when to share the
values of input-output variables is done by a compile
time data-flow analysis. Similarly, the compiler of Trilogy checks whether
the output variables are assigned values in all branches of a predicate
(whether all input-output variables are initialized). There
is also a check to see that if-then-elses do not backtrack
(either before thens or among the branches), e.g.


   if x = 1 | x = 2 then
     x <> 1 & P(x)
   else
     ......
   end

The above is dissalowed by the compiler if x is output or
symbolic (logical), but is OK if x is input or input/output.
Thus we can guarantee that the negation of the formula
before a then is always properly computable.
Consequently if-then-elses and the formulas before thens
are compiled without any settings of choice points. We are
just releasing a version where non-backtracking ors (|)
(implemented by jumps instead of choice points) are permitted
in procedures (this is useful for the writing of the Trilogy
counterparts of Pascal's boolean functions).

There are two situations where the run-time tags on Trilogy values
are present:


1) the tags discriminating the union values, these should
   be also present in Pascal programs.

   For instance, the universal type U of all Trilogy's values has a 
   form of a union:

      U = R(R) | S(S) | P(U,U)
  
   The tags R(eal), S(tring), and P(air) are thus present in the
   values of U variables.

   If a value is not of a union type (tuple, list, array,
   integer, enumerated-type etc.) then it contains no tags,
   except of course the tags of any of its union constituents.

2) When a variable is of symbolic (logical) mode then Trilogy
   uses the type specific tags to identify the constraints
   attached to the variable (=, <, <>, etc.).


Because of the typing, modes, pred/proc modifiers and a quite extensive
data-flow analysis the compiler of Trilogy produces a procedural
code of Pascal-like quality while offering all the high-level
comfort of symbolic values with their associated constructors
and destructors as we know it from Prolog.

------------------------------
   
Date: 16 Mar 88 23:35:51 GMT
From: sanjay@arizona.edu  (Sanjay Manchanda)
Subject: Logic of Database Updates

 I have worked on doing database updates in Prolog in a  "logical"
fashion.   A database update is essentially an assignment  on the
database.   If we are going to update the database, why not first
develop a logic for reasoning about database assignments, and then
mechanize it in the true logic programming tradition?   A dynamic
logic is a reasonable choice for this task, since  dynamic logics
were developed to reason about programs which  explicitly manipulate
their state (i.e.   do assignment).    I have developed a dynamic
logic for reasoning database updates that doesn't look much like  the
dynamic logic's that you may have seen, but it leads to a simple
extension of Prolog.  

Instead of going into the logic, I will briefly explain the extension of 
Prolog. Richard introduced it rather well in a previous
message, so let me borrow some of his words.
>Roughly speaking, there are three classes of predicates:
>
>	pure predicates (don't depend on things that change)
>
>	state predicates (depend on things that change, but change nothing)
>
>	transition (or dynamic) predicates (express a relation between states)
>
>For example, we might say
>
>	p(X) :-
>		<-fred(X)> q(X).
>
>p(X) is true in a world W if there is a world W1 such that
>	-(fred(X), W, W1)			-- roughly, retract
>and	q(X) is true in W1.
>
>Note that this doesn't change W.

There are two sets of predefined dynamic predicates, +p and -p for
every pure predicate p.    Actually, to avoid some thorny
implementation and semantic problems, p is restricted to be a pure
predicate that is defined entirely by ground Prolog facts.    For
obvious reasons, such a predicate is called a database  predicate.
New dynamic (or transition) predicates can be defined by means of
Update Rules.   For example, we might say  

       add_flight(Fno, Src, Dest) <--
                 airport(Src), airport(Dest), 
		 <+flight(Fno, Src, Dest)>.

The use of the `<--' instead `:-' signals that a dynamic predicate is
being defined.    Here the semantics of add_flight(Fno, Src, Dest) is
a transition from a world W to a world W1, such that (airport(Src),
airport(Dest)) is true in W, and   W1 is obtained from W by adding
the fact flight(...)   to W.   Thus, viewed as an operator, + is
roughly equivalent to assert.  

The rule may be used in a top level query like:

   :-     <add_flight(20, 'LA', 'OHARE')>reachable('LA', 'JFK')

which is true in a current world W if there exists W1 accessible
through the meaning of add_flight(..), and reachable('LA','JFK') is
true in W1.  Assume that reachable is the transitive closure of the
flight relation.  The execution of the query is not very different
from Prolog execution.   Thus the call <+flight(..)>  will return a
new (world) database in which reachable(...)   will be evaluated.  If
this evaluation fails, backtracking will cause the inserted fact
flight(...)  to be removed.  Similarly, deletion on the database is
undone on backtracking.  

If the query succeeds, it will return a new updated database and
display to the user, all the changes that have been made to the
current database.  The user can then choose to commit these changes
and make them permanent, or reject them and leave the database
unchanged.    

The language has a well-defined declarative semantics, and a syntax
that reflects this semantics.   This makes it considerably better
than using assert and retract for database updates.   As an example,
note that in my proposed extension, updates are  statically scoped.
If p(X) is pure predicate or a state predicate, the database  is
guaranteed  to remain unchanged after it is executed.  This  can be
quite significant for compiler and database query optimization.

I did not allow updates to rule-defined predicates because  I wanted
to guarantee that (not p(a)) was true after  executing <-p(a)>.
However, I think that can extend the treatment if I use a weaker
semantics.   I will mail copies of [1], [2] and [3] to anyone who
requests them.  My apologies to Richard for forgetting to mail him a
copy of my paper.  

-- sanjay

 References:

[1] Sanjay Manchanda and David Scott Warren.
A Language for Database Updates.
In Jack Minker, editor, Foundations of Deductive Databases and
  Logic Programming, Morgan-Kaufmann, Los Altos, CA, 1987.

[2] Sanjay Manchanda, Soumtira Sengupta, and David S. Warren.
Concurrent Updates in a Prolog Database System
Technical Report 86/28, Department of Computer Science,
SUNY at Stony Brook, Stony Brook, NY 11794,
December 1986, Revised Feb 1987.

[3] Sanjay Manchanda
A Dynamic Logic Programming Language for Relational Updates.
Phd Thesis, SUNY at Stony Brook, Stony Brook, NY 11794, December
1987.

------------------------------

Date: 17 Mar 88 03:49:59 GMT
From: munnari!vuwcomp!lindsay@uunet.uu.net  (Lindsay Groves)
Subject:  mine embarrassingly simple problem

I'll save Richard saying it -- this doesn't say much about the program, and 
certainly doesn't explain why ancestral cuts are supposed to be necessary.
Could you describe the problem in a bit more detail and illustrate just 
how the need for ansectral cuts arises?  Perhaps a simplified version of the
problem could be used to illustrate the point.  An example would certainly 
help.

-- Lindsay Groves

------------------------------

Date: 23 Mar 88 01:16:54 GMT
From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  mine embarrassingly simple problem

In that case, why not just code it as

	map(Function, Network) :-
		generate(Function, Network),
		test(Network),
		!.

	test(Network) :-
		lemma(Network, StopCondition).

More generally, suppose that you had several cases:

	test(Network) :-
		lemma(Network, ~~~),
		!(map(_,_)),
		p(...).
	...
	test(Network) :-
		lemma(Network, ~~~),
		!(map(_,_)),
		q(...).

Then you could recast this as

	map(Function, Network) :-
		generate(Function, Network),
		test(Network, Continuation),
		!,
		finish(Continuation, ...).

	finish(p, ...) :-
		p(...).
	...
	finish(q, ...) :-
		q(...).

	test(Network, p) :-
		lemma(Network, ~~~).
	...
	test(Network, q) :-
		lemma(Network, ~~~).

The basic idea is to redesign your "test" code so that it breaks into
three pieces: before-the-cut, the ancestral cut, and after-the-cut,
and then unfold the call to it so that the cut is exposed in "map".

------------------------------

Date: 20 Mar 88 20:55:02 GMT
From: lagache@violet.Berkeley.EDU  (Edouard Lagache)
Subject: My views on developing a PROLOG standard 

          To help get the creative juices flowing on those position papers,
     I thought I would throw in my two cents worth on this proposed
     standard.

          While I am not really qualified to make much commentary on the
     subject (So what? that has never stopped me before!), there are a
     number of peripheral matters that I would like to see addressed.

          The matter of greatest concern for me is the question of whose
     standard will be the standard?  The BSI group is a British standard;
     Now I hear that the French are working on their own standard (the AFNOR
     group).  All this is fine and good except that in all likelihood the
     resulting standards will have about as much similarity with each other
     as the French and English (natural) languages do (never mind the fact
     that neither standard will have have much to do with existing practice)
     - This is progress!?!

           Perhaps this is a wild fantasy on my part, but I would really
     like to see ONE (1) standard.  That standard should be agreed upon not
     just by the British and the French, but by ALL the major users of
     PROLOG which includes (at the very least) most of Europe, Japan, and
     the U.S.  It seems to me that someone should bug the ANSI standard
     committee, NOT to come up with their own standard (Lord have mercy on
     all those "C" and FORTRAN users once the new standards are in place),
     but to take part in an international effort to come up with the before
     mentioned 1 PROLOG standard.

          Fantasies aside, I do have a few comments on the BSI standard.  On
     the specifics of the "grimoire", I can only steal a quote from the
     venerable Michael Clancy: "Do the right thing".  In this case, "Do the
     right thing" means try to capture existing practice as much as possible
     (see "lots of smoke" on exactly what existing practice means on the
     FORTRAN SIG).  I do believe that asking the question of how existing
     code would run under the new standard is a valuable measure of the
     success at capturing existing practice.  Unless there is a *strong*
     reason to change syntax, the new standard shouldn't depart from
     existing practice.  Thus, I have read Richard O'Keefe's comments on his
     perceptions of the standard syntax with real concern.  Until I see a
     "reasonable" reply from the standards committee, I am inclined support
     Richard O'Keefe's position on this matter.

          At the end of last week there was some discussion of the standard
     library.  Here I have one suggestion, make the library big enough so
     that people don't have to reinvent the wheel all the time.  I took a
     lot of heat for my imfamous PROLOG libraries, while the code quality
     was perhaps inadequate, I believe that the concept was valuable.  Even
     in as rich a language as Franz LISP, I still found the need for 1600
     lines of additional general purpose functions.  So there is a lot of
     room expansion in PROLOG.

          I would like to suggest defining a separate set PROLOG libraries,
     much in the same way the UNIX "C" library is (was?) defined
     independantly of the language.  In this area, I would strongly suggest
     various levels of libraries.  There should be some core set that would
     be required for the standard language, then additional standards would
     be defined for supplemental libraries.  <*Fantasy mode on*>  Ideally
     the standards committee should provide source code for those
     supplemental libraries in the core standard language (when possible),
     so that anyone using any standard PROLOG implementation could use the
     full set of libraries (if more slowly than if all the predicates were
     builtin). <*Fantasy mode off*>  In any case, Everybody knows that the
     first thing PROLOG system implementors do is to embellish on the
     standard core library, so wouldn't it be nice if the standard included
     a few hundred predicates to keep those implementors busy upgrading
     their product in a standard way (maybe I should have kept Fantasy mode
     on?)

          The last thing I would really like to see is some vast
     improvement in the standard user interface tools.  Even if not all
     hardware can support it, I would like to see some standard way to
     access windows, i/o devices (i.e. mice), and or forth.  If one could
     write complete applications in PROLOG that had portable "bells and
     whistles", that would make PROLOG much more attractive for those trying
     to make polished products for end users, since that would greatly reduce
     porting problems (I know, Fantasy mode is still on!)

     Still dreaming in California,

    -- Edouard Lagache

------------------------------

Date: 23 Mar 88 01:09:49 GMT
From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  My views on developing a PROLOG standard (long but fun!)

Wrong.  Roger Scowen of NPL get the thing started; since the NPL is in
England he naturally got the thing started as a BSI project.  AFNOR are
not developing a rival standard;  they have been collaborating with the
BSI group for a long time now, and the Formal Specification is French work.
(While many people will find it the most confusING part of the BSI material,
it is arguably the least confusED.)  The whole thing has now become, I hear,
an ISO "work item", and the more recent BSI documents bear ISO reference
numbers.

>      That standard should be agreed upon not
>      just by the British and the French, but by ALL the major users of
>      PROLOG which includes (at the very least) most of Europe, Japan, and
>      the U.S.

Hear hear.  And don't forget the South Pacific (home of NU Prolog and CLP)
or Israel (home of Wisdom Prolog).

>      I took a
>      lot of heat for my imfamous PROLOG libraries, while the code quality
>      was perhaps inadequate, I believe that the concept was valuable.

Too right.

>           The last thing I would really like to see is some vast
>      improvement in the standard user interface tools.  Even if not all
>      hardware can support it, I would like to see some standard way to
>      access windows, i/o devices (i.e. mice), and or forth.

I understand that agreement on the Common Lisp binding for X is at least
a year away.  Plagiarism being the sincerest form of flattery, I suggest
that it might be an idea to wait for the Lisp people to do the work, and
then transliterate as much of it as possible.  Or would a 'curses'
binding be of more immediate use?  Either way, I don't see any need for
a standard way to access Forth; Postscript maybe, but not Forth (:-).

-----------------------------

Date: 21 Mar 88 09:26:04 GMT
From: nsc!taux01!shahaf@decwrl.dec.com  (Shahaf Moshe)
Subject:  mine embarrassingly simple problem
First I would like to make two comments:
* I am a NOVICE (in Prolog).
* I do not claim that in my application Ansectral Cut are a MUST. I wrote it on
  a system were it was a feature and I used it. Since its not available in
  Quintus Prolog, I asked for help.

About the application,
The program looks for best mapping of a Boolean function onto a set of logic
primitives such as 
	X * Y * Z maps to: 2inputAnd( 2inputAnd( X, Y) , Z)
	               or: 3inputAnd( X, Y, Z)
	       
	       Since the search space is huge I used Ansectral Cut to abort
mapping once I get some "STOP CONDITIONS".

The program looks like:

map(Function,Network) :-
			generate(Function,Network),
			test(Network).
test(Network) :-
		lemma(Network,StopCondition),
		!(map).	    %this cut aborts the process.

I hesitate to post longer description on the net. If anyone would like to
get more elaborated data I will mail upon request.

------------------------------

Date: 19 Mar 88 03:04:08 GMT
From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  behavior of read/get0 at end_of_file

I thought you might be interested to know what the BSI committee say.

In document PS/236, "Draft minutes, Prolog Built-In Predicates meeting,
10 December 1987", we find

	4 Design criterion

	<name deleted> suggested: "Whenever possible, a predicate with
	a side effect should always succeed and never instantiate
	variables."

This of course rules get0/1 and read/1 out entirely.  That may not be
what <name deleted> _meant_, but it _is_ what the minutes say he _said_.
As far as I can tell, the real intent is to rule out retract/1, which
is disliked because it unifies its argument with the thing you removed.
The minutes show that Paul Chung proposed naming the standard clause-
removing predicate delete/1 instead of retract/1.  Good on yer, mate!
This should not be construed as endorsement of the name delete/1, but
as praise for Paul Chung's good standardisation manners.

------------------------------

Date: 22 Mar 88 15:56:23 GMT
From: mcvax!unido!ecrcvax!micha@uunet.uu.net  (Micha Meier)
Subject:  behavior of read/get0 at end_of_file

	This is true, we have to distinguish various uses
	of get0/1. The above example is indeed easier
	written when get0/1 fails at the eof, because the is_endfile/1
	test is not needed. However, most often one wants to do more
	with the character rather than just test the eof, and only
	then the differences are meaningful.

	By the way, get0/1 does *not* exist in BSI, it uses get_char/1 instead,
	and its argument is a character, i.e. a string of length 1.
	This means that the type 'character' is inferred from
	the type 'string' (and not the other way round like in C).
	Does anybody out there know what advantages this can bring?
	It is independent on the character <-> integer encoding,
	but this only because explicit conversion predicates have
	to be called all the time.

	In his tutorial to the SLP '87 Richard has taken another
	representation of a finite automaton which is more
	appropriate:

	s1 :-
		get0(Char),
		s1(Char).

	s1(0'a) :-
		s2.
	s1(0'b) :-
		s1.
	s1(-1) :-
		accept.

	
	The difference is, that if one wants to perform some action
	in some states, this must be done *before* reading the next character,
	i.e. just at the beginning of s1/0. Such representation can
	be more easily converted to the BSI's variant of get:

	s1 :-
		% do the corresponding action
		( get0(Char) -> s1(Char)
		;
		  accept
		).

	s1(0'a) :-
		s2.
	s1(0'b) :-
		s1.

	Note that the eof arc has to be merged into s1/0 in this way
	since if we'd write it like

	s1 :-
		s1_action,
		get0(Char),
		!,
		s1(Char).
	s1 :-
		accept.

	then after an eof we would backtrack over s1_action and undo
	what we've done.

	I must say, none of the two seems to me satisfactory. Richard's
	version is not portable due to the -1 as eof character. We can
	improve this into

	s1(X) :-
		eof(X),
		accept.
	s1(0'a) :-
		s2.
	s1(0'b) :-
		s1.

	and hope that the compiler will unfold the eof/1 inside the
	indexing mechanism, otherwise we have choice points even
	if the code is deterministic.
	The BSI version is much more arguable, though. Having to
	wrap a disjunction (and a choice point) around the get0/1 call
	suggests that for this application the BSI choice is not
	the appropriate one. It is interesting to note, however, that
	it could work even with nondeterministic automata, where the BSI's
	failure was (I thought) more likely to cause problems.

	For a Prolog system it is better to have get0/1 return
	some *portable* eof (e.g the atom end_of_file, for get0/1
	there can be no confusion with source items) instead of
	some integer.
	
	  This, however, just shifts the problem up to read/1:
	BSI objects that if it returns e.g. the atom end_of_file
	then any occurrence of this atom in the source file
	could not be distinguished from a real end of file.
	In this case, a remedy would be the introduction of
	a term with a local scope (e.g. valid
	only in the module where read/1 and eof/1 are defined) and
	using eof/1 instead of unifying the argument of read/1 with
	the end_of_file term. Hence read/1 would return this term
	on encountering the file end and eof/1 would check whether
	its argument is this term.

--Micha

------------------------------

Date: 20 Mar 88 20:51:12 GMT
From: lagache@violet.Berkeley.EDU  (Edouard Lagache)
Subject: Seeking opinions on BSI PROLOG standard proposal.

               I spent a few hours carefully collecting all the
          comments on the proposed BSI PROLOG standard that have been
          posted to the PROLOG SIG.  The result was a 160Kb file!  The
          reason for this exercise in tedium was my desire to write an
          article on the pros and cons on this standard for the next
          issue of the PROLOG Forum newsletter.  However, for obvious
          reasons, I am not particularly anxious to try to comb through
          all them bytes of complex argumentation, and I am not
          optimistic that I could do any of the participants justice.

               Thus, I would like ask those persons who expressed some
          substantial position on the new PROLOG standard, if they
          might be interested in submitting to the PROLOG Forum
          something equivalent to a short (1-3 page) position paper on
          the standard.

               Because we are such a new group, our editorial policies
          are still in the process of coalescing, but at the moment I
          would think that a very informal sort of piece of the sort
          that you might post to the net would be very acceptable.

               Should you have any interest and/or questions please
          direct them to me, and I will do my best to answer them or if
          necessary to rely them to our newsletter editor.

               I am looking forward to a lot of interesting commentary!

-- Edouard Lagache

    P.S. A minor detail, but anyone wishing to submit a text can simply
         e-mail it to this account.  If prefered, one could send an
         PC or Mac compatible disk with the text in "flat ASCII" format to:
              The PROLOG Forum
              P.O. Box 3826
              Redwood City, CA, 94064, USA.

------------------------------

Date: 21 Mar 88 16:40:44 GMT
From: eagle!icdoc!doc.ic.ac.uk!cdsm@ucbvax.Berkeley.EDU  (Chris Moss)
Subject:  BSI 

Forwarded for Roger Scowen -- KRG0@gm.rl.ac.uk
 
RESPONSE TO COMMENTS FROM RICHARD O'KEEFE ON PROLOG STANDARDIZATION
 
GENERAL RESPONSE
 
Richard O'Keefe started by saying that he would respond to the
mailing from Chris Moss. In fact many comments refer
to a document (Prolog syntax, Draft 4.1) that
most news readers (and members of the ISO and BSI panels) will
not have seen.
 
This seems somewhat unfair on readers who will be unable to judge 
whether draft, criticism, or rebuttal is justified.
 
First some general comments. The objective is to define an
International Standard for the programming language Prolog.
This means that standard conforming programs will run correctly
on standard conforming processors, neither more nor less.
It will not limit implementers from introducing new features and
facilities into their Prolog compilers. 
 
Neither will it mean programmers cannot use such extensions; only
that if they do, their programs will not conform to the standard.
 
But a standard will permit people and companies to write applications
and libraries that will run on any conforming implementation
and thus give them a framework in which to work. In particular, such users
and their customers will not be restricted to a single implementation.
A standard will also give teachers, authors and students a common core 
of useful Prolog.
 
Once a feature has been included in a standard, it is almost
impossible to remove. The committee remembers that Fortran has been 
burdened with arithmetic if statements and computed goto statements.
In Prolog we hope to avoid such legacies if possible.
So some features of Edinburgh Prolog will not be in the standard 
because although they fulfilled a need at one time, they are
not a sensible longterm solution.
 
Now some replies to specific criticism.
 
DIVERSITY OF EXISTING PROLOG SYSTEMS
 
Chris Moss has produced tests that give
different results on every system tested so far. Perhaps there
is rather more diversity than Richard O'Keefe realizes.
One objective has been to define a syntax where many existing 
systems would not generally disagree on the meaning of 
standard-conforming programs. 
 
PROLOG CONTROL STRUCTURES AS SYNTAX
 
>	(3) The attempt to describe Prolog control structures as *syntax*
>	    is fundamentally misdirected.
 
This is a matter of opinion. One reason for regarding Prolog control
structures as *syntax* is so that a person or program reading
a Prolog program can always recognize its overall structure.
 
NOTICE OF MEETINGS
 
 Meetings are planned and advertised several months in advance,
for example, the following meetings are already planned:
 BSI, London on Thursdays 2nd June, 1st Sept, 1st December 1988.
Any extra meetings to discuss the syntax will be on the previous
day (i.e. 1st June, etc); any meetings to discuss built-in predicates
will be a week later, i.e. 9th June, etc.
Everyone who wishes to attend is welcome. I admit that pressure of
work means that some papers are sent only a week before the meeting.
This is ample for British members of a British panel, but not for 
Californian members. 
But other papers will have been sent four or five weeks earlier.
 
All comments, whether they are received before or after a meeting,
are read and considered.
 
',' and '&' AS OPERATORS
 
 It is not intended that it will be possible to declare ',' and '&'
as operators.
 
A MISTAKE IN COMMENTS
 
	/** By L22, this is not a legal comment **/
 
Thank you. This will be a valid comment in standard Prolog despite
the error in this draft.
 
QUOTE OPERATORS USED AS OPERANDS
 
 Richard O'Keefe realizes that the above example is intended to be
syntactically incorrect in the standard. When operators are
used as operands, there many problems of possible ambiguity.
A cure is still under discussion, but some problems are
avoided by the rule that "An operator used as an operand must be
bracketted".
 
AN INFIX CONS OPERATOR
 
 We are still considering the problems posed by the multiple uses of '.',
i.e. as a decimal point, as an infix cons operator, and as a clause
terminator. At the same time we desire to make layout characters
unimportant in determining the meaning of a program.
Several possibilities have been suggested and are under consideration.
 
NEGATION

It is intended that Standard Prolog will not contain 'not' or '\+'.
Standard Prolog will not require systems to implement true
logical negation and it would be misleading to include an 
operator or predicate that implies that they have done so.
Instead the way is left open for processors to implement a version
of 'not' as an extension and still remain standard conforming.
Standard Prolog will contain a built-in predicate 
that implements 'negation by failure', i.e.
      fail_if(G) :- call(G), !, fail.
      fail_if(_).
 
A PARSER AS STANDARD
 
 A program that resolves ambiguity implicitly is not acceptable as
defining a standard; there must be further definition.
One reason is that a program specifies too much. Some features need to
remain 'implementation dependent' because we must not specify
them, for example: the accuracy and largest values of floating point
numbers, or the integer value corresponding to a character.
 
Another reason is that it is harder to understand and find errors.
 
DISCLAIMER AND CONCLUSION
 
Never rely on working papers and draft standards. They are subject to
changes and review. All documents and working papers, however
confidently expressed, are also subject to review. There will be no
standard until the member bodies of ISO have approved it.
 
The next working drafts will incorporate changes arising from further
consideration and the comments received (including those from
Richard O'Keefe).
 
Many countries, but not at present USA, have national Prolog panels
coordinating their views on the emerging standard. I encourage all 
Prolog implementers and users to participate in this effort in order that
the eventual standard is one that preserves the best of the past
and also provides development paths for the future.
 
-- Roger Scowen

-------------------------------

Date: 23 Mar 88 05:11:45 GMT
From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  BSI syntax
Message-Id: <797@cresswell.quintus.UUCP>
References: <234@gould.doc.ic.ac.uk>
Sender: prolog-request@score.stanford.edu
To: prolog@score.stanford.edu

My postings were in fact a response to Chris Moss's mailing.  They were
not confined to the content of that mailing, true.  It seemed to me that
Chris Moss's mailing implied that the BSI syntax was in a satisfactory
state, and that it wasn't as difference from the de facto standard as
people feared.  I set out to show that neither of those statements is
true, and I believe that I succeeded.

Many comments did refer to a document that most news readers won't have
seen.  But then, most news readers won't have seen ***ANY*** of the BSI
documents.  Am I then to say nothing?   As for fairness to readers,
(a) I was quoting from the very latest document I had.
    Surely it would be more unfair to quote from something I believed
    to have been superseded?
(b) The "February 88" and "Feb 88" documents arrived in my mailbox here
    in the same week.  I had no way of telling who had or had not
    received the document I was quoting.  All I knew was that this was
    the latest document available, sent to me by the author.
(c) In order to permit readers to judge for themselves whether my
    criticisms were justified, I quoted extensively from the document.
    I did not ask anyone to take it on faith that this or that was the
    case:  where the grimoire appeared to say something particularly
    silly I exhibited the rules responsible.  This is unfair?

> First some general comments. The objective is to define an
> International Standard for the programming language Prolog.
> This means that standard conforming programs will run correctly
> on standard conforming processors, neither more nor less.
> It will not limit implementers from introducing new features and
> facilities into their Prolog compilers. 
>  
> Neither will it mean programmers cannot use such extensions; only
> that if they do, their programs will not conform to the standard.
>  
This is a little misleading.  The general rule in other languages is
that implementors can add extensions, provided that such extensions
are either illegal or undefined in the standard.  Thus a Pascal compiler
can provide alphabetic labels as an extension.  But an implementor
should not provide an extension which alters the meaning of a program
which the standard would have ruled legal.

Let's apply this to the case of :- read(_). directives in a file which
is being consulted or compiled.  Specifically, let's consider a file
which looks like
	:- read(_).
	p(a).
and has nothing else in it.  Does this define p, or does it not?  The
BSI grammar, in all versions, provides the syntax of entire files:
according to the grimoire this MUST mean exactly one directive followed
by exactly one clause.  Since this is a defined and legal file, it would
be most improper for an implementor to give it any other meaning.
Therefore, reading out of a file being compiled or consulted is NOT
a permitted extension.  (This wouldn't bother Quintus, but it is legal
in some other Prologs.)

Let's apply this to another case:  functor/3.  It has always been the
case in DEC-10 Prolog that functor(1, 1, 0).  In at least one draft of
the BSI built-in predicates document, this has been required to raise
an error.  (BSI Prolog includes an error handling facility; needless
to say it doesn't look like IF/Prolog's or M-Prolog's or ...)  So a
BSI conforming program is entitled to rely on this error being raised,
and an implementor may NOT provide DEC-10 compatibility.

The ANSI C committee have found it necessary to explicitly indicate
which identifiers may be used by implementors.  (The list includes
all identifiers starting with "_" or "str" and there are others I
can't remember right at the moment.)  Why is this?  Because the
programmer needs a guarantee that the identifiers he has chosen for
his code won't be in conflict with an implementation.  For example,
(not)/1 is not defined in the BSI stuff, so Scowen says that an
implementation is free to define it.  But if the implementation is
free to do so, then the programmer ISN'T.  Since setof/3 is not in
the BSI Prolog language, a program which defines

	setof(List, Set) :-
		setof(List, [], Set).		

	setof([], Set, Set).
	setof([Head|Tail], Set0, Set) :-
		(   member(Head, Set0) ->
		    setof(Tail, Set0, Set)
		;   /* not member(Head, Set0) */
		    setof(Tail, [Head|Set0], Set)
		).

is a standard-conforming program.  But a Prolog system which is exactly
BSI except for providing setof/3 as an extension is a conforming processor.
Will such a conforming program run correctly on such a conforming
processor?  You must be joking.  So, taken in their ordinary sense,
the claim that "standard conforming programs will run correctly on
standard conforming processors", while true of some standards, is NOT
true of the BSI work, unless "standard conforming processors" is
construed very strictly as meaning "providing NO additional built-in
predicates".

You will recall that Fortran 77 provides the EXTERNAL and INTRINSIC
statements precisely to cope with this problem, and that ANSI C
provides the reserved-to-implementors list and #undef precisely to
cope with this problem.  BSI Prolog does have some reserved words,
but is ludicrously far from providing a solution to this problem.

> So some features of Edinburgh Prolog will not be in the standard 
> because although they fulfilled a need at one time, they are
> not a sensible longterm solution.

Let's be realistic.  There are languages on the horizon which are much
better approximations to logic programming than Prolog.  (NU Prolog has
been around for a while.)  There are lots of software engineering needs
which old Prolog completely failed to address, such as modules.  (Last
I heard, the consensus of the BSI Modules subcommittee was that they
would probably never agree.)  I think we ought to regard Prolog as a
stopgap; and that the goal of the standard should be to protect EXISTING
investments in Prolog.  Frankly, advocates of BSI Prolog, with its
use of user-supplied atoms as stream names, are in no position to talk
about sensible solutions.

************************************************************************
** It would be most interesting to have an explicit list of the features
** of Edinburgh Prolog which fulfilled a need at one time and are now
** disliked by the committee, and a description of their replacements.
************************************************************************

> >	(4) The basic structure of the BSI approach to syntax has been
> >	    to cut the Gordian Goose.  That is, instead of regarding the
> >	    (actually rather low) diversity of Prolog syntax as an
> >	    opportunity to be solved by making the language more powerful
> >	    (e.g. having a table-driven tokeniser), it has been treated as
> >	    a problem to be solved by inventing a new, more restricted,
> >           language.
>  
> Well, yes and no. Chris Moss has produced tests that give
> different results on every system tested so far. Perhaps there
> is rather more diversity than Richard O'Keefe realizes.
> One objective has been to define a syntax where many existing 
> systems would not generally disagree on the meaning of 
> standard-conforming programs. 
  
The amount of diversity one perceives depends on which "Prolog" systems
one decides to include in one's sample.  My sample includes only systems
whose implementors _tried_ to be Edinburgh (or at least Clocksin &
Mellish) compatible.  For example, AAIS Prolog is openly and frankly
not an Edinburgh-compatible system.  We may (and should) look to it for
ideas, but we should not include it in a sample of "Edinburgh compatible"
Prologs.  BIM Prolog has its own unique syntax; while we should perhaps
include the '-c' syntax of BIM Prolog in the sample, we should not
include BIM Prolog's native syntax.  If we go by numbers, then Turbo
Prolog should determine the syntax of standard Prolog.  If not by numbers,
by what?  Simple justice suggests that the Prologs to look at are the
Prologs whose authors TRIED to be compatible with one another.  Prudence
suggests the same sample.

But even if the diversity among the Prologs whose authors didn't suffer
from NIH-itis is much greater than I believe, that doesn't answer my
point.  What I said was that the diversity should be regarded "as an
opportunity to be solved by making the language more powerful (e.g.
having a table-driven tokeniser)".  [As an aside, this is no more than
Lisp and PopLog already have.]  It turns out that it is quite easy to
write a tokeniser which can handle all of
	ALS Prolog
	Arity Prolog
	BIM Prolog native syntax
	C Prolog
	DEC-10 Prolog
	PopLog	(nested comments)
	Quintus Prolog
	Stony Brook Prolog
and can almost handle ADA [ADA is no longer a trademark], simply by fiddling
with a table.  AAIS took exactly this approach (though their tokeniser is
not as flexible as mine).  I found it necessary to support several kinds
of quotes in my tokeniser:
	ATMQT		- the quoted thing is an atom (')
	STRQT		- the quoted thing is a string ($)
	LISQT		- the quoted thing is a list (")
	CHRQT		- the quoted thing is a character (`)
Suppose the standard were to adopt this approach, then they could rule,
if they wished, that the standard assignment was "->STRQT, with nothing
being assigned LISQT.  That needn't prevent me reading my existing code:
I'd be able to change the table while reading my old files.
[The best approach seems to be to associate a read table with a stream;
 naturally this is the approach PopLog takes.]

What I have in mind here is that a file would start with a directive
such as
	:- use_syntax(dec10).
or	:- use_syntax(standard).
or	:- use_syntax(als).

Especially if the tokeniser were made available to user code (as it is
in the DEC-10 Prolog library, or built-in in NU Prolog), the result would
be a much more powerful language at very little cost to the implementor.
And conversion from old dialects to the BSI dialect would be enormously
simplified.

Do we need to come up with a "best possible" tokeniser for the standard?
Of course not.

Again, what are we to do about syntactic variations, such as the
treatment of operators?  My answer, in 1984, was that the standard
should not specify read/1 and write/1, but should specify
	standard_read/1
	standard_write/1
and should allow users to redefine read/1 and write/1, but require
that the initial definitions be the standard one.  consult and compile
should use read/1, not standard_read/1, so that someone who wanted to
read M-Prolog files into standard Prolog could do so by suitably
defining read/1.

Now, if you are a self-appointed standards committee member determined
to impose your vision of what is a "sensible longterm solution" on
every Prolog user whether they like it or not, this sort of approach
won't seem all that attractive.  But if, like me, you think that the
people who matter in all this are the people who have paid money to
USE Prolog, and if, like me, you think that the fact that M-Prolog
is appalling is no reason to make life any harder for people with a
lot of data in M-Prolog format than we have to, you'll think that
letting people do

	read(Term) :- magyar_read(Term).

is obviously the way to go.	(It doesn't much matter how you install
your own code in the hook, the important thing is that there should be
a read-hook where you can install your own reader to be used by compile
and consult.)

> PROLOG CONTROL STRUCTURES AS SYNTAX
> >	(3) The attempt to describe Prolog control structures as *syntax*
> >	    is fundamentally misdirected.
> This is a matter of opinion. One reason for regarding Prolog control
> structures as *syntax* is so that a person or program reading
> a Prolog program can always recognize its overall structure.

It is not a matter of opinion.  Either I am right about this, or I am
wrong.  There is a very important reason for my belief:  Prolog is
simply not the sort of language for which this kind of thing can WORK.
Consider the difference between

	foo(X, P, Q, L) :- bag(X, (P & Q), L).
				  ^^^^^^^
and
	de_morgan((P & Q), (R | S)) :- de_morgan(P, R), de_morgan(Q, S).
		  ^^^^^^^
The first is code, and the treatment of it in the grimoire is appropriate.
(That is, it will be mapped to whatever "(and ?P ?Q)" would have been
mapped to in the BSI Lisp-like syntax.)
But the second is data, and the treatment of it in the grimoire is
NOT appropriate.  It will be mapped to whatever "(and ?P ?Q)" would
have been mapped to in the BSI Lisp-like syntax, but it SHOULD be
mapped to whatever "[& ?P ?Q]" would be mapped to.

If we consider a slightly different example:

	baz(X, P, L) :- bag(X, P, L).
			       ^
and
	de_morgan(not(P), R) :- de_morgan(P, R).
					  ^
we find the opposite problem: the second is data and will be mapped to
whatever "?P" will be mapped to in the BSI Lisp-like syntax, but the
first is code, and should be mapped to whatever "(and ?P)" would be
mapped to, BUT IT WON'T BE.

The trouble is that the grimoire tries to guess whether something is
code or data by looking at its form, but that's the wrong place to
look:  the place to look is the predicate being called.  And the
trouble is that we can't build that information into the grammar,
because the programmer can define new predicates with code-like arguments.

Let me stress this:
	the whole basis of the build-it-all-into-the-syntax approach
	is the assumption that code is code and data are data and
	never the twain shall meet.
This is true of Pascal.  It is true of Fortran.  It is almost true of C.
But it is utterly false of Lisp and Prolog.  A grammar of this type does
not make SENSE for Prolog any more than it makes sense for Lisp.

I hereby wager US$100, payable once to Chris Moss, that if the next draft
of the grimoire attempts to maintain this rigid distinction between code
and data, I will be able to find inconsistencies like the ones above in
it.  I don't think it's Chris Moss's fault:  if anyone can find a way of
working around this basic mistake (not HIS mistake, by the way, this is
the kind of grammar the BSI committee have always wanted), I'm sure that
Chris Moss could.  I make my wager *despite* my belief in Chris Moss's
competence, because I believe that it is _impossible_ for this approach
to work.  (If I do not receive said draft by the end of this year, the
wager will expire.)

> ',' and '&' AS OPERATORS
> > Oddly enough, if one takes the grimoire literally, the user CAN
> > declare ',' and '&' as operators, and can use them in that form.
> > However, ',' and '&' cannot possibly have the same precedence as
> > "," or "&" in BSI Prolog, and it seems clear that (A ',' B) and
> > (A '&' B) must be different terms.  
>  
> It is not intended that it will be possible to declare ',' and '&'
> as operators.
>  
There is nothing in the grimoire to say so, and it is a very odd restriction.
Intentions are beside the point:  all that matters is what the documents
actually say.  It *is* the intention that it should be possible to write
','(A,B) as a term, and it remains the case that ','(A,B) and '&'(A,B)
must be different terms, and if we take the grimoire literally, neither of
them can be the same as (A,B) or (A&B).

[Yes, I know about (P|Q) and (P;Q) in Dec-10 Prolog.  I have always thought
 and said that this was a mistake, and I think it is one of the very few
 areas where a difference between the standard and existing practice might
 be justifiable.
]

> QUOTE OPERATORS USED AS OPERANDS
> >	compare(R, X, Y) :-
> >		( X @> Y -> R = >
> >		; X @< Y -> R = <
> >		;	    R = =
> >		).
>  
> Richard O'Keefe realizes that the above example is intended to be
> syntactically incorrect in the standard. When operators are
> used as operands, there many problems of possible ambiguity.
> A cure is still under discussion, but some problems are
> avoided by the rule that "An operator used as an operand must be
> bracketted".
>  
Well, it would be more accurate to say that I COMPLAIN that it is
intended to be syntactically correct in the standard.
There isn't any problem of possible ambiguity here whatsoever.

	) :- (		:- must be infix
	X @> Y		@> must be infix
	Y -> R		-> must be infix
	R = >		= must be infix or suffix, has no suffix reading
	= > ;		> must be atom or prefix, has no prefix reading
	> ; X		; must be infix
    and so on
Now if = and > _both_ had a suffix reading, (R = >) would be ambiguous.
Since neither of them has, there is no ambiguity here at all.

The elimination of ambiguity is not a very good argument for breaking
existing UNAMBIGUOUS code!

> NEGATION
> >	not Goal :-		% "not" is not a built-in operator
> >	    (	ground(Goal) -> \+ Goal		% neither is "\+".
> >	    ;	signal_error(instantiation_fault(Goal,0))
> >	    ).
> It is intended that Standard Prolog will not contain 'not' or '\+'.
> Standard Prolog will not require systems to implement true
> logical negation and it would be misleading to include an 
> operator or predicate that implies that they have done so.
> Instead the way is left open for processors to implement a version
> of 'not' as an extension and still remain standard conforming.
> Standard Prolog will contain a built-in predicate 
> that implements 'negation by failure', i.e.
>       fail_if(G) :- call(G), !, fail.
>       fail_if(_).

My main point here was a semantic one.  Most other control structures
are defined in the grammar.  It seems odd that
	( G -> fail ; true )	should be in the grammar, but that
	fail_if(G)		which is identical in effect, should not.
Because one of these forms is in the grammar and the other isn't, they
have different properties.  For example,
	( 1 -> fail ; true )	is syntactically illegal, but
	fail_if(1)		is syntactically legal.
There are other differences as well.

If BSI Prolog contains fail_if/1, then it WILL contain '\+', but with
a different name.  Why not use an existing name for an existing
operation?  Looks to me like nonhicinventusitis.  \+ is a crossed-out
|-, meaning, obviously enough, "not provable".

> A program that resolves ambiguity implicitly is not acceptable as
> defining a standard; there must be further definition.
> One reason is that a program specifies too much. Some features need to
> remain 'implementation dependent' because we must not specify
> them, for example: the accuracy and largest values of floating point
> numbers, or the integer value corresponding to a character.
>  
> Another reason is that it is harder to understand and find errors.

It is harder to understand and find errors in a program you can run
than in a never-used-anywhere-else formalism?  Judging by the results,
this is the opposite of the truth.

What is the difference between the public-domain DEC-10 Prolog parser
and the BSI grimoire?  Both are programs, in a formalism based on logic.
Neither is more explicit or less explicit than the other, and both are
of similar size.  So what is the difference?  The difference is that
the public-domain DEC-10 Prolog parser CAN be run, HAS been run, and
has had most of the mistakes knocked out of it by actual experience.
The BSI grimoire is in a new formalism, the definition of which is
provided in ***NO*** BSI document (so that I had to keep guessing what
things meant), and each of the three drafts I have seen was riddled
with errors from end to end.  I haven't told you about all the problems
I found; there are nearly as many problems as rules!

The BSI Prolog group HAVE specified the integer value corresponding to
a character:  they require the ISO 8859 character set.  GREAT!
The DEC-10 public-domain ***parser*** does NOT specify the integer
value corresponding to a character (that's the tokeniser's job).
{The old tokeniser did have ASCII codes built in, but the current
version of the tokeniser uses 0'x syntax for the appropriate
constants to avoid that problem.}
If the BSI committee are so concerned to avoid character code problems,
how come they haven't got anything like 0'x or `x` (in a standard which
doesn't have to cope with existing code that uses ` as an atom, `x` is
a good notation for character code constants)?

The public-domain tokeniser doesn't specify anything more about floating
point numbers than what they look like, it relies on being provided with
a number_chars/2 predicate (which we want ANYWAY) do to the actual
conversion.

Note that the BSI grimoire says NOTHING about what happens if you write
a constant which exceeds the capacity of your implementation.  Is the
program
	p(1.2e3456).
a BSI-conforming program or not?  Well, syntactically it is, but the
lexical rules say nothing about what it MEANS.  For all that the
grimoire or any other BSI document I can recall says to the contrary,
a Prolog implementation which reads this as
	p(0.0).
is conforming.  This kind of thing is a real portability problem; it
exists with respect to integers too.  Is 1000000000000000000 a legal
Prolog term?  According to the grimoire, yes.  What does it mean?
The grimoire doesn't say.

> DISCLAIMER AND CONCLUSION
> Never rely on working papers and draft standards. They are subject to
> changes and review. All documents and working papers, however
> confidently expressed, are also subject to review. There will be no
> standard until the member bodies of ISO have approved it.

But what ELSE is there to comment on?

> Many countries, but not at present USA, have national Prolog panels
> coordinating their views on the emerging standard. I encourage all 
> Prolog implementers and users to participate in this effort in order that
> the eventual standard is one that preserves the best of the past
> and also provides development paths for the future.
>  
> Roger Scowen, 11 March 1988

Sorry, but it's too late.  Prolog implementors and users should have been
invited to contribute before the committee went on a four-year binge of
inventing their own language.  I explicitly suggested some years ago that
the people at WISDOM should be invited to participate, and was told that
that was out of the question.  I have put a lot of effort into writing
responses to the BSI stuff, and for all the feedback I've had I might as
well have been shouting into a vacuum.  The BSI committee having been
resolute in their contempt for existing Prolog users (I have repeatedly
urged that they should explicitly adopt a principle of not breaking
existing code without strong necessity, as the ANSI C committee did, and
the last I heard was that they had explicitly rejected any such idea),
I cannot regard "preserves the best of the past" as anything but a sick
joke.

Look, if you want to preserve the best of the past, why have you
renamed findall/3 to bag/3?  Why have you adopted ESI Prolog-2's
streams rather than Arity/Prolog's streams, despite having been
told about the problems?  Could it be something to do with the
fact that the author of that part of the standard worked for ESI,
not for Arity?  Why have you dropped nl/0 from the standard?  Why
is there no notation for character constants such as PopLog provides?
Why is the error handling facility all new, rather than resembling
either IF/Prolog or M-Prolog?

I have tried, I really have tried, to arouse interest in the BSI work
here in the US.  Do you know what has got in the way?  As soon as I
show people any of the BSI documents (take the 'standardisation issues'
documents as an example) they say "what a pack of turkeys" and assure
me that there is nothing to worry about.  I remain desperately worried
that there will be a BSI/ISO Prolog standard, and that it will be as
bad as the current drafts, and that it will do a great deal of damage.
What *really* worries me is that the people on the BSI committee don't
seem to realise how bad it is.
------------------------------

End of PROLOG Digest
********************

restivo@POLYA.STANFORD.EDU (Chuck Restivo) (07/04/88)

Date: Thursday, 5 May 1988 0:1:43-PST
From: Chuck Restivo (The Moderator) <PROLOG-REQUEST@POLYA.STANFORD.EDU>
Reply-to: PROLOG@POLYA.STANFORD.EDU>
US-Mail: P.O. Box 4584, Stanford CA  94305
Subject: PROLOG Digest   V6 #28
To: PROLOG@POLYA.STANFORD.EDU


PROLOG Digest           Friday, 1 Apr 1988      Volume 6 : Issue 28

Today's Topics:
     				Query - Parallel Compilers,     				
		     Implementation - end_of_file & Strings & Eliza
----------------------------------------------------------------------------------------------------------------------------

Date: 23 Mar 88 14:26:19 GMT
From: mcvax!dutrun!dutesta!ignacio@uunet.uu.net  (Ignacio GARCIA ALVES)
Subject: Parallel prolog compilers and interpreters

We are interested in PARALLEL PROLOG COMPILERS AND INTERPRETERS, like for 
example PARLOG and CONCURRENT PROLOG.

But now the problem: WHERE CAN WE FIND THEM?

So we would like to hear the answers to the following questions:
- where can we order them?
- what are the prices?
- who has already such a compiler or interpreter to hear their experience?
- what are the hardware and software requirements?

We do have the following hardware:
- VAX, Berkeley Unix 4.1
- RT, AIX
- PC

All information is welcome either by post or email!

POST:   Ignacio GARCIA ALVES & Mark KORSLOOT
        Delft University of Technology
        Faculty of Electrical Engineering
        Section Computer Architecture
        Mekelweg 4
        2628 CD  DELFT
        THE NETHERLANDS

EMAIL:  !mcvax!dutrun!dutesta!ignacio.uucp
    or  !mcvax!dutrun!dutesta!mark.uucp

-----------------------------

Date: 24 Mar 88 03:06:23 GMT
From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  behavior of read/get0 at end_of_file

I just grepped through the UNIX [UNIX is a trademark of AT&T] manuals,
and all I could find was the function feof(Stream).  None of the UNIX 
utilities I am familiar with uses "eof" to signify end of file.
Franz Lisp does something interesting:
	(ratom [Port [Eof]])
	(read  [Port [Eof]])
	(readc [Port [Eof]])
return the Eof argument (which defaults to nil) when you read the
end of the file, so you can get whatever takes your fancy.

> so i think we could maybe abandon the end_of_file notation of Quintus (sorry
> for you Richard, a compatibility switch could very easily turn it back anyway),

But it ***ISN'T*** a Quintus notation!  This is the notation used by
	DEC-10 Prolog
	EMAS Prolog
	C Prolog
	Quintus Prolog
	Stony Brook Prolog
	ALS Prolog
	Expert Systems International Prolog-2
	AAIS Prolog (in "Edinburgh" mode only)
and doubtless many others.  end_of_file IS the "de facto" standard.
Poterie's suggestions are good ones, but in order to overthrow the
de facto standard, they would have to be MUCH MUCH better, and they
aren't.

> but it is not an important point as the aim would be to discipline one's
> programming style by systematically using the test form: 
> 	eof(Term) 
> and never ever explicit the EOF term itself. Portability is great.

Beware.  While Quintus Prolog offers the library predicate
	is_endfile(?EndMarker)
there are other Prolog systems, such as AAIS Prolog, where there is a
predicate with a similar name which takes a Stream argument:
	is_eof(+Stream)
in AAIS Prolog means "is it the case that Stream is positioned at its end?".
Yes, portability is great, but would it not be more just to reward those
people (such as SICS, Saumya Debray, ALS, and others) who have tried to
provide it, by standardising their solution?

> As a side effect, close/1 is
> not strictly necessary anymore as the following sequence does the job:
> 		eof(EOF), put(EOF)
Um, what about INPUT streams?  And there is another reason for wanting
close/1:  it will close a stream which is not the current output stream.

------------------------------

Date: 26 Mar 88 05:25:23 GMT
From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  End-of-file handling

In article <2403@zyx.UUCP>, bd@zyx.UUCP (Bjorn Danielsson) writes:
> I can't understand why there should be a "strait-jacket solution" to this
> kind of problem. Why not put in enough flexibility to allow for the most
> obvious cases? In Z-Prolog, (which was never designed to be Edinburgh
> compatible) the "read" predicate can handle end-of-file in three different
> ways, depending on an optional argument:
> 	(1) signal an error,
> 	(2) fail,
> 	(3) return a value supplied by the programmer.
> 
Oh, __HOW__ I wish you were were handling the I/O part of BSI substandard!
That's EXACTLY the right sort of attitude for a standard designer.

I think that there are sound technical reasons for regarding fail-at-end
as a straight-out blunder, and I have used PL/I and Fortran enough to
convince me that end-of-file is NOT an error and shouldn't be treated
like one.  (Reading *past* end-of-file is another matter, which is one of
the things I have against fail-at-end.)  But a more powerful operation,
which is not perceptibly harder to implement, which will let me synthesise
the operation I want, and let BIM synthesize the operation they want,
that's exactly the right thing to do in the standard.

Oddly enough, I had intended to mention Algol 68.  Files in Algol 68 are
rather interesting.  One of the things you can do is say

	FILE example file;
	...
	logical file ended OF example file :=
	    (FILE file parameter) BOOL: (
		# return FALSE to get default action (e.g. error report) #
		# return TRUE to say "corrected, please try again" #
		# or jump out #
	    );

Interlisp does the same sort of thing:

	(WHENCLOSE file 'EOF (FUNCTION (LAMBDA (file) (* action *)) ))

So even if we decide to feed this goose instead of killing it, there are
at least three options:
   1.	specify in each call what action to take on end of file
	read(Stream, Term, EofAction)
	-- This affects 'read' only.

   2.	specify per stream what action to take on end of file
	eof_action(Stream, EofAction)
	-- This could affect any form of input.

   3.	allow both.

One of the constraints which is of interest to Quintus is that whatever the
end of file action is, it has to make sense if the stream was being used by
C or Lisp code.  The nice thing about sticking with -1 as the character
end-of-file mark and adopting option 3 is that it does this.

Note though that as I mentioned in my previous message, just because the
host operating system indicates an end-of-file condition doesn't mean that
it isn't possible to read any more from the file.  (UNIX fans will know
about 'tail -f' and why it is useful...)  The standard should, I said in
'84, include a predicate for testing whether the stream is really ended.
If the stream is not really ended, it should be possible to resume reading.

------------------------------

Date: 22 Mar 88 16:55:39 GMT
From: mcvax!unido!ecrcvax!bruno@uunet.uu.net  (Bruno Poterie)
Subject:  behavior of read/get0 at end_of_file

I do not think that having read/1 returning an atom on EOF is a bad thing.
If you take as an example certain UN*X tools, they read their input from
a file (typically stdin) until finding a line composed of a single dot.
So it is perfectly legal to submit a file which contains a dot-line in the
middle if you want only the first part to be feeded to the tool. Same thing
for Prolog, if you have a huge file full of various facts but want only say
the first 100 to be used as input in your test program, then simply add
the EOF mark before line 101. I would then prefer to have it as a directive:
		...
		:- eof.

so that it is not a bare fact but actually a command to the consulting tool
that it have to EOF this input source. It is then coherent with other
directives like:
		...
		:- [file3,file4].
		...
which actually order the consulting tool to insert at this point the content
of the named files. I believe that the notation "eof" is quite standard in
the UN*X system and already in some Prolog, including as a test predicate for
this very term:
		... read(Term), eof(Term) -> ...

so i think we could maybe abandon the end_of_file notation of Quintus (sorry
for you Richard, a compatibility switch could very easily turn it back anyway),
but it is not an important point as the aim would be to discipline one's
programming style by systematically using the test form: 
	eof(Term) 
and never ever explicit the EOF term itself. Portability is great.

	Now for the get0/1 [or get_char/1/2]: having it returning an otherwise
impossible value, say an atom as suggested by Micha, is ok if the returned
thing is an integer representing the ascii code [or ebcdic] of the character.
using the same term as the one returned by read/1, and consequently the same
test predicate as only mechanism to check for EOF, would greatly improve the
compactness and consistency of the i/o system. As a side effect, close/1 is
not strictly necessary anymore as the following sequence does the job:
		eof(EOF), put(EOF)
Because obviously put/1 must handle the same term in the same way (I am afraid
that outputing CHAR modulo 256 would not work in this case).
I nevertheless believe that EOF == -1 is a clearer convention, returning an
object of the same type but out of the normal range of normal input, and
is already the UN*X convention. It would not force put/1 to accept it as EOF
character, as it would be outputed as: -1 modulo 256 (or 512) == 255. Passing
-1 to UN*X putchar() does not generate an EOF!

Ok, enough delirium tremens for today. My main point is: the character i/o
should provide a very low level facility, with no hypothesis about the use
which could be made of them. Using read(Term) and eof(Term) provides an
uniform, simple, elegant and portable mean of performing i/o at Prolog term
level. Using get0/1 implies you are interested in the real bits contained
in your input support, so you want to control it at a low level. Returning
the -1 value is portable and low-level, because independant of ascii or
any other character set. Alternatively, returning eof and using the same
eof(Char) test predicate would be again low-level, portable, and free of
any supposed semantic. More important, most of prolog input loops may be
adapted with this scheme at low cost. Failing at EOF, however, would mean
full rewriting of those applications and system libraries.

------------------------------

Date: 22 Mar 88 10:29:39 GMT
From: mcvax!prlb2!kulcs!bimandre@uunet.uu.net  (Andre Marien)
Subject: end_of_file treatment in prolog

Sorry for being inaccurate: we should have taken the trouble of explaining what
BIMprolog's predicate eof/0 does and it is different from what Richard's
at_eof/0 does:
eof/0 succeeds only after a read/1 or get0/1 has failed because end of
file was encountered
so, let me change buggy_read into:

        non_buggy_read(Term) :- bim_read(Term), ! .
        non_buggy_read(end_of_file) :- eof .

actually, eof/0 is written using a predicate in_status/1 which unifies
its argument with an integer indicating the 'status' of the input stream

> end-failure approach, despite having asked Bart Demoen at the Prolog
> Benchmarking Workshop for enlightenment on this point.  Again, this

Perhaps you asked Andre' Marien, but not Bart Demoen: he was not at the Prolog
Benchmarking Workshop

Now about the transformation of

        s1: a -> s2.
        s1: b -> s1.
        s1: $  -> accept.

to a prolog procedure;

1. the textbook uses an explicit end of file marker, so it is clear that the
   behavior of Cprolog's get0/1 suites better in this transformation;
   still, I would rather represent a state by a predicate with arity 0 and let
   it get its character itself:
   
        s1 :- get0(X) ,
        	(X = a , s2 ;
        	 X = b , s1 ;
        	 X = -1 , true
        	) .

      this of course with get0/1 behaving like in Cprolog

2. Now, do it with BIMprolog's get0/1, I will call it BIMget0 so that you will
   always know which behavior to expect

   s1 :- BIMget0(X) , (X = a , s2 ;
        	       X = b , s1
        	      ) .
   s1 :- eof .
   
   this doesn't look very nice, but
   
	a. I would expect that in a parser, in most states eof indicates an
	   error, so that error recovery must be done, which is very easy
	   (in prolog) by backtracking to the appropriate level (state) in the
	   parser; so in most states, there would be no clause like s1 :- eof.
	   then, on eof, s1 fails as it does on input characters different
	   from a or b

	   see Pascal : an endpoint is the endmarker, and occurrence of eof
	                    during tokenizing means an error
	   see Prolog : every clause must have an endpoint; eof could only
	                    occur after a clause

	b. prolog (at least BIMprolog) is used for other things than writing
	   tokenizers - actually, tokenizers should not be written at all: they
	   should be generated - and in an administrative application written in
	   prolog, using BIMread or BIMget, the programmer can feel at ease:
	   after a successful BIMread or BIMget, he has got data; it is in a
	   way impossible for him to forget testing for eof, because otherwise
	   the execution of the program would never have gone so far

3. A more general approach can be used, using a state transition table.
   The previous program can be derived from this by partial evaluation.
   In the triangle puzzle problem discussion, R.O'K argued that this
   approach is more general.

	step_state(accept) :- ! .
	step_state(From) :- BIMget0(X), !,
			From : X => New,
			step_state(New) .
	step_state(From) :- BIMeof,
			From : '$' => New,
			step_state(New) .

	s1: a => s2.
	s1: b => s1.
	s1: '$' => accept.

	If eof is to be treated as an error, remove the last clause of
	step_state/1.
	Eof is handled in one place, in Cprolog one should add :

		transit(si,-1,error) .

	for all states, or write :

		state(From) :-	get0(X), noteof(X), !,
				transit(From,X,New),
				state(New) .

		noteof(-1) :- !, fail .
		noteof(_) .
 
To sum up: there is an appropriate level of testing for eof: BIMread and BIMget
(and BSIread and BSIget for that matter, to answer one of Richard's questions
and worries) allow you to do this testing of eof at these levels only, while
read and get0 of Cprolog force you to test it after every input operation

------------------------------

Date: 23 Mar 88 09:54:10 GMT
From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  behavior of read/get0 at end_of_file

In article <518@ecrcvax.UUCP>, micha@ecrcvax.UUCP (Micha Meier) writes:
> 	By the way, get0/1 does *not* exist in BSI, it uses get_char/1 instead,
> 	and its argument is a character, i.e. a string of length 1.
> 	This means that the type 'character' is inferred from
> 	the type 'string' (and not the other way round like in C).
> 	Does anybody out there know what advantages this can bring?
> 	It is independent on the character <-> integer encoding,
> 	but this only because explicit conversion predicates have
> 	to be called all the time.

I find it extremely odd to call a string of length one a character.
It's like calling a list of integers which contains one element an
integer.  Do we call an array with one element a scalar?

I haven't commented on the BSI's get_char/1 before because for once they
have given a new operation a new name.  There are two problems with it.
A minor problem is that the result being a string, they can't represent
end of file with an additional character, so the fail-at-end approach is
hard to avoid.  (Not impossible.)  There is an efficiency problem:
something which returns an integer or a character constant can just
return a single tagged item, but something which returns a string either
has to construct a new string every time, or else cache the strings somehow.

For example, Interlisp has a function which returns you the next character
in the current input stream, represented as an atom with one character in
its name.  (Well, almost:  characters `0`..`9` are represented by integers
0..9.)  This was quite attractive on a DEC-20, where you could just compute
a table of 128 atoms once and for all.  It wasn't too bad on VAXen either,
where the table had to have 256 elements.  But it because rather more
clumsy on the D machines, which have a 16-bit character set.  (Can you say
"Kanji"?  I knew you could.)  So the alternatives I can see at the moment
are
    o	construct a new string every time.
    o	precompute 2^16 strings.
    o	cache 2^8 strings, and construct a new string every
	time for Kanji and other non-Latin alphabets.
    o	not support Kanji or other non-Latin alphabets at all.
(Can you say "Cyrillic"?  How about "Devanagari"?  You may need the
assistance of a good dictionary; I used to mispronounce "Devanagari",
and probably still do.)

I wrote that
> >For example, the arcs
> >	s1: a -> s2.
> >	s1: b -> s1.
> >	s1: $  -> accept.
> >would be coded like this:
> >	s1(0'a) :- get0(Next), s2(Next).
> >	s1(0'b) :- get0(Next), s1(Next).
> >	s1(- 1) :- true.
Meier says that
> 	In his tutorial to the SLP '87 Richard has taken another
> 	representation of a finite automaton which is more appropriate:
> 	s1 :-
> 		get0(Char),
> 		s1(Char).
> 
> 	s1(0'a) :-
> 		s2.
> 	s1(0'b) :-
> 		s1.
> 	s1(-1) :-
> 		accept.
There wasn't time to go into this in detail in the tutorial, but it
should be obvious that the first approach is more general:  in particular
it can handle transitions where (perhaps because of context) no input is
consumed, and it can handle lookahead.
>	Such representation can
> 	be more easily converted to the BSI's variant of get:
> 	s1 :-
> 		% do the corresponding action
> 		( get0(Char) -> s1(Char)
> 		;
> 		  accept
> 		).
This doesn't generalise as well as the end-marker version.
Here is the kind of thing one is constantly doing:

	rest_identifier(Char, [Char|Chars], After) :-
		is_csymf(Char),
		!,
		get0(Next),
		rest_identifier(Next, Chars, After).
	rest_identifier(After, [], After).

See how this code can treat the end marker just like any other
character:  because it doesn't pass the is_csymf/1 test (copied from
Harbison & Steele, by the way) we'll pick the second clause, and there
is no special case needed for an identifier which happens to be at the
end of a stream.

The fail-at-end approach forces us not only to do something special
with the get0/1 in rest_identifier/3, but in everything that calls it.
(In the Prolog tokeniser, there are two such callers.)

The point is that if-then-elses such as Meier suggests start
appearing all over the place like maggots in a corpse if you adopt
the fail-at-end approach, to the point of obscuring the underlying
automaton.

> 	I must say, none of the two seems to me satisfactory. Richard's
> 	version is not portable due to the -1 as eof character.

If the standard were to rule that -1 was the end of file character,
it would be precisely as portable as anything else in the standard!
In strict point of fact, the Prolog-in-Prolog tokeniser was written
in DEC-10 Prolog for DEC-10 Prolog, and used 26 as the end of file
character, and 31 as the end of line character.  It took 5 minutes
with an editor to adapt it to Quintus Prolog.  I wish C programs
written for UNIX took this little effort to port!

> 	for a Prolog system it is better to have get0/1 return
> 	some *portable* eof (e.g the atom end_of_file, for get0/1
> 	there can be no confusion with source items) instead of
> 	some integer.

It is important that the end-of-file marker, whatever it is, should be
the same kind of thing, in some sense, as the normal values, so that
classification tests such as is_lower/1, is_digit/1, and so on will
just fail quietly for the end-of-file marker, not report errors.  Since
end of file is rare, we would like to test the other cases first.
Pop-2 on the Dec-10 returned integers almost all the time, except that
at the end of a stream you got an end-of-file object which belonged to
another data type (there was only one element of that data type, and it
printed as ^Z).  This was in practice a major nuisance, because before
you could do anything other than an equality test with the result, you
had to check whether it was the end of file mark.

I have been giving out copies of the Prolog-in-Prolog tokeniser to show
how easy it is to program character input with the Edinburgh Prolog
approach.  If someone would give me a tokeniser for BSI Prolog written
entirely in BSI Prolog using the fail-at-end approach, and if that
tokeniser were about as readable as the Prolog-in-Prolog one, that would
go a long way towards convincing me that fail-at-end was a good idea.

> 	BSI objects that if [read/1] returns e.g. the atom end_of_file
> 	then any occurrence of this atom in the source file
> 	could not be distinguished from a real end of file.

That's not a bug, it's a feature!  I'm serious about that.  At Edinburgh,
I had the problem that if someone asked me for help with Prolog, they
might be using one of four different operating systems, where the end
of file key might be
	^Z
or	^D
or	^Y
or	something else which I have been glad to forget.
No problem.  I could always type
	end_of_file.
to a Prolog listener, and it would go away.  Oh, this was so nice!
In fact, on my SUN right now I have function key F5 bound to
"end_of_file.\n" so that I can get out of Prolog without running the
risk of typing too many of them and logging out.

Another thing it is useful for is leaving test data in a source file.
One can do
	<declarations>
	<clauses>
	end_of_file.
	<test cases>
and include the test cases in the program or not just by moving the
end_of_file around.

Ah, you'll say, but that's what nested comments are for!
Well no, they don't work.  That's right, "#| ... |#" is NOT a reliable
way of commenting code out in Common Lisp, and "/* ... */" is NOT a
reliable way of commenting code out in PopLog.  But end_of_file, in
Edinburgh Prolog, IS a reliable way of commenting out the rest of the file.

> 	In this case, a remedy would be the introduction of

Prolog needs a remedy for end_of_file like Elizabeth Schwarzkopf
needs a remedy for her voice.

Before taking end_of_file away from me, the BSI committee should supply
me with a portable way of exiting a break level and a reliable method of
leaving test cases in a file without having them always read.

------------------------------

Date: 24 Mar 88 08:58:35 GMT
From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject: behavior of read/get0 at end_of_file

Just to continue with the get0 topic:

	The fail-at-end approach rests on an assumption
	which deserves to be made explicit, because it is false.

What is the assumption?   That receiving the end-of-file indication from
an operating system indicates that there is nothing further to read in
that stream.  This is false?  Yes.

Let's ignore 4.2BSD sockets, V.3 Streams, non-blocking I/O, VMS
concatenated files, and other esoterica which one doesn't expect
BSI Prolog to cope with.  Let's just consider terminals.

In Tops-10 (home of DEC-10 Prolog):
	end-of-file from the terminal is a software convention (^Z).
	You can just keep reading from the terminal after that, and
	in fact that's exactly what DEC-10 Prolog does.

In UNIX (original home of C Prolog):
	end-of-file from the terminal is a software convention
	(EOF character typed after an empty line).
	You can just keep reading from the terminal after that, and
	in fact that's exactly what C Prolog does.

In VM/CMS, using SAS Lattice C
	end-of-file from the terminal is a software convention
	(some magic string, which defaults to "EOF", but it is
	trivially easy for a program to change it -- use afreopen()).
	I believe that you can keep reading from the terminal after
	that, but I haven't tried it myself.

On a Macintosh, using ALS Prolog
	end-of-file from a window is a software convention
	(you click on "End of File" in the "Edit" menu).
	All windows and streams remain live after that, and
	you can just keep reading, and that's what ALS Prolog does.

On a Xerox Lisp Machine, using Xerox Quintus Prolog
	end-of-file from a TEXEC window is a software convention.
	All windows and streams remain live after that, and
	you can just keep reading, and that's what XQP does.

[The sample of Prologs is not of interest here; my point is that there
 are several *operating systems* with this characteristic.
]
So the rule actually followed in Edinburgh-compatible Prologs is that
    -   the sequence of characters codes returned by get0/1 is
	the sequence of characters delivered by the source
    -   with the end-of-file marker inserted every time the
	host indicated the end-of-file condition
    -	Prolog receives through get0/1 as many characters and as many
	end-of-file markers as there are; any attempt to read past the
	end of this union stream is an error.  Not a failure, an error.

It happens that when you are reading from disc files, most operating
systems will indicate the end of file condition once.

Are terminals the only kind of file for which multiple end-of-file
conditions are plausible?  No.  The convention for tapes is that a
single tape-mark (usually reported as an end-of-file condition) is
merely a separator; a tape as such is terminated by a double tape-mark.
Thus a Prolog program copying one tape to another (this is a reason why
we might want put(-1) NOT to close a file; if it does anything special
on a tape it should be to write a tape-mark) might want to keep reading
after seeing an end-marker.

------------------------------

Date: 24 Mar 88 15:29:47 GMT
From: mcvax!ukc!dcl-cs!simon@uunet.uu.net  (Simon Brooke)
Subject:  Strings

In article <776@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>Xerox Lisp uses lists for bignums to this very day.

Yes, true. But please don't assume this means it is efficient. For
example, I recently benchmarked a Xerox 1186 running Interlisp (Koto)
against the new Acorn Archimedes running Arthur Norman's Cambridge Lisp.
Generally the Arch was a bit faster, reflecting the simpler lisp and
faster processor. But running (fact 1000) it was 321 (three hundred and
twenty one) times faster - and this must reflect grotesque inefficiency in
Xerox' bignum code.

------------------------------

Date: 24 Mar 88 18:35:05 GMT
From: eagle!icdoc!doc.ic.ac.uk!cdsm@ucbvax.Berkeley.EDU  (Chris Moss)
Subject:  Strings

I haven't contributed to the string discussion because I don't believe I
know all the answers. But I do have strong reservations about the current
Edinburgh implementations. Let me air them:

1. They don't get printed properly by "write". I don't like seeing
"Prolog" come out as [80,114,111,108,111,103]. OK, I can define a
"writestring", but not use it within a bigger structure without pain.  

Now here's an odd thing: there is no writestring routine in the Quintus
library that I can discover! Not in the built-ins or the (extensive)
library!  

What does that tell us about the use of strings? It suggests to
me that people actually always use atoms for this purpose, and somewhere 
in their code is an implicit definition: 
    writestring(String) :- name(Atom,String),write(Atom).  

Note that in most systems this involves an entry in the symbol table 
(reasonably slow) and a limit of 256 (or maybe 512) characters.

MuProlog DOES print out "Prolog" as a string, wherever it occurs.
Presumably it has to scan the list first. It uses list format whenever
there is a integer outside the range 32-127 in the list (it also gets tabs
right tho I don't understand why it finishes at 127 not 126). That's a
pretty good heuristic, tho I can imagine it going wrong on occasions. e.g.
if I read in a clause over several lines the string will contain newlines,
so my DCG debugging will still look horrid!

2. I don't like having ASCII values in my programs. With a certain amount
of discipline and inefficiency one can get round that, by saying, for 
instance:
    lowercase(X) :- "a"=[A], "z"=[Z], X>=A, X=<Z.
but it's not an ideal solution (tho close to normal arithmetic habits in
Prolog). These type of routines tend to be efficiency sensitive. 

OK, there is the 0'a notation (another way of writing 97 if you're using
ASCII). Now that DOESN'T work in MuProlog, or Poplog or ...

On efficiency I mostly agree with Richard. I too like strings to be lists,
and can't see the real benefits of a string type, though you don't tend to
miss what you never had!

So, what I would like to see is not a string type but a CHARACTER type. 
Small integers work in Ed-Prolog mainly because they're efficient for get
and put -- there's no symbol table lookup. It would be nice to treat
single character atoms as their ASCII value, but that's wrong because one
does want to hang things off atoms. So they would have to be a separate
data type. As far as notation is concerned I have no better suggestion
than 0'a tho I don't much like it.

Now I don't object to Pascal's ORD (tho Modula II's ORD is TERRIBLE.
It is defined as CARDINAL so one usually has to say VAL(INTEGER,ORD("a"))).
But one-way transfers aren't much of a problem semantically, so I
wouldn't object to the C solution, which allows them to be used in arithmetic
contexts. e.g. Num is Ch-0'0 or Letter =<0'z.

Thus the main difference with the present systems would be:
  1. 0'a wouldn't unify with 97. (I assume)
  2. write(0'a) would print out 0'a.
  3. write("abc") or write([0'a,0'b,0'c])  would print out as "abc".
  4. One would need a "CHR" function (but not ORD) in arithmetic
expressions.

The question is, "is it worth the change"?  For my pennyworth the answer
is "yes". NOT having a character type makes Prolog as archaic as Fortran
IV in computer-science terms. I don't much like the string type idea. And
if you say "you proposed it" you're wrong. I've only been concerned with
syntax and semantics, not the built-in-predicates (there are limits to the
number of committees any sane person can attend!). Strings have been mostly
discussed in the BIPs meetings. Most of my suggestions at main committee
meetings have been ignored! When it comes to the semantics one needs a
character type even in the present proposal.

The biggest anti-argument is that all sorts of Prolog programs might break
in weird ways because of difference 1. I don't know the answer to that.

-- Chris Moss
 
------------------------------

Date: 21 Mar 88 08:45:07 GMT
From: otter!kers@hplabs.hp.com  (Christopher Dollin)
Subject:  Prolog implementations in Lisp

Pop11 is like Lisp[*3] in that it has dynamic typing, dynamic store allocation
with garbage collection, first class (really, *1st*, not 1.5st) procedures,
lexical scoping, and run-time access to the compiler. It is unlike Lisp in that
it has a concrete syntax, open stack, partial application, user-defined
datatypes that aren't just funny uses of vectors or lists, and coroutines.

I think I'll go and lie down. Notefeet follow.

[*1] Systems Designers market Poplog in the USA and UK for commercial clients.
     Sussex University deal with educational establishments in the UK, and
     Robin Popplestone does so in the USA.

[*2] OK, quite a lot really.

[*3] When I say Lisp I mean Vulgar - sorry, Common - Lisp.

Regards,
-- Kers              

-------------------------------
                   
Date: 25 Mar 88 04:39:20 GMT
From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject: My views on developing a PROLOG standard

In article <240@gould.doc.ic.ac.uk>, cdsm@ivax.doc.ic.ac.uk (Chris Moss) writes:
> Richard's certainty that the
> Prolog world begins and ends with Edinburgh is not shared in France!

I have no such certainty.  I think the Prolog world includes Israel,
Japan, Australia, Portugal, the USA, Hungary, China[*], and all sorts of
places.  The plain fact of the matter is that there are two sorts of
Prolog systems:  ones whose authors have tried to provide some sort of
compatibility with other Prologs, and ones whose authors have let their
imaginations rip.  What the compatible Prologs are compatible with is
not Prolog-II or Waterloo Prolog, but Clocksin&Mellish.

[*] I am credibly informed that the PRC uses an unauthorised translation
    of Clocksin & Mellish as the main Prolog text, so presumably the
    French Prologs are of small concern to them.

------------------------------

Date: 20 Mar 88 20:47:39 GMT
From: lagache@violet.Berkeley.EDU  (Edouard Lagache)
Subject: An Eliza-like problem solving assistant (400+ lines).

    The following program is the mockup of the Eliza-like problem solving
    assistant that was demonstrated at the March 10 meeting of the PROLOG Forum.
    The program is the result of 3 late night work, and NO claims of
    correctness or efficiency are expressed on implied.  On the contrary,
    suggestions for expansion or improvement are most welcome.  As stated
    earlier, it is hoped to turn this program into a group project, so
    we hope that there is plenty of room for expansion!

    There are some calls to my imfamous PROLOG libraries.  The 'window'
    and 'set_attribute' calls will only work on a Texas Instruments PC,
    so I leave it to you to omit, or port these calls to your system.
    There is one call to the predicate 'nthelem', I have enclosed a copy
    of the predicate at the end of the file.  There may be other calls
    that I have forgotten, if so let me know and I will provide the needed
    code.

    Hack to your hearts delight!

    -- Edouard Lagache

/* File: 'consulta.pro' */
/******************************************************************************/
/*                                                                            */
/*                  An A.I. Consultant for PROLOG Programmers                 */
/*                                                                            */
/*       This program is intended to serve as a "intelligent consultant"      */
/*  for PROLOG programs to turn to when encountering some impasse in a        */
/*  programming project.  The program is based on the "Eliza" program, but    */
/*  it designed to provide comments that might foster the user to "solve"     */
/*  his/her own problem.                                                      */
/*                                                                            */
/*               A collaborative project of the PROLOG Forum.                 */
/*    Release - 1.00,  March - 1988,  Copyright(C) 1988, The PROLOG Forum     */
/*                                                                            */
/*  Credits: The concept of an "Eliza" type program to help users with        */
/*           problem solving was first proposed (as far as we know) by        */
/*           Professor Charles Woodson of the School of Education at          */
/*           U.C. Berkeley.  He also built a small system in LISP for the     */
/*           purposes of demonstrating the concept to members of his LISP     */
/*           programming course.                                              */
/*                                                                            */
/******************************************************************************/

/*>> 'gethelp' is the routine that the user can call to get access to the <<*/
/*>> system.  E. Lagache, Ver-1.0, 3/88                                   <<*/
gethelp :- tell('_WINDOWS'), make_window(0,15,14,64), set_attribute(magenta),
           clear_screen, set_attribute(white),
           prtstr("Please describe your problem, type 'quit.' to resume work"),
           nl, converse, close_window, tell(user).

/*>> 'converse' is the main "looping" routine.  It takes a list of words <<*/
/*>> and searches for keywords.  Then it generates a response based on   <<*/
/*>> keywords.  The responses are randomized to make the system more     <<*/
/*>> "humanlike".   E.L.,  Ver-1.0, 3/88                                 <<*/
converse :- set_attribute(white), prtstr("<>-> "), set_attribute('yellow'),
            read_sentence(Request), nl, remove_duplicates(Request,Request1),
            make_reply(Request1,Reply), set_attribute(cyan),
            print_reply(Reply), nl, continue(Request1).

/* continue makes the recursive call to 'converse' if the user doesn't want */
/* quit */
continue(['quit','.']) :- set_attribute(white), pause.
continue(_) :- converse.

/* 'pause' uses the interval function to simply carry out some time consuming */
/* task to make a delay between the exit prompt, and the closing of the       */
/* window.                                                                    */
pause :- interval(1,X,10), fail.
pause.

/* 'print_reply' simply prints out the list of items recursively */
print_reply([]).
print_reply([Item|Rest]) :- print(Item), put(32), print_reply(Rest).


/*>>------------------------------------------------------------------------<<*/
/*>> 'make_reply' generates a response to a keyword in the users input text <<*/
/*>> it keeps a list of keywords and appropriate responses, and chooses one <<*/
/*>> randomly to provide a "natural" appearance.                            <<*/
/*>> E. Lagache,  Ver - 1.0, 3/88                                           <<*/
/* Exit comment */
make_reply(['quit','.'],['Thank','you','I','hope','these','comments','were',
                         'useful.']
          ).

/* Main test, select some set of keywords, test if they match, if so succeed */
/* otherwise fail and look at another possibility.                           */
make_reply(Sentence,Reply) :- word_class(Keywords,Responses),
                              intersection(Keywords,Sentence,List),
                              List \== [], !, length(Responses,Top),
                              irandom(1,Top,Number),
                              nthelem(Responses,Number,Reply).

/* if no keywords are found, then use default responses */
make_reply(_,Reply) :- default_responses(Responses), length(Responses,Top),
                       irandom(1,Top,Number), nthelem(Responses,Number,Reply).

/* 'remove_duplicates' returns a list that contains only one of each item.  */
/* This is necessary for the 'intersection' predicate, and makes the search */
/* less time consuming.  E.L. 3/88                                          */
remove_duplicates([],[]).
                             /* First case, don't copy duplicate items */
remove_duplicates([Item|Rest],NewRest) :- member(Item,Rest), !,
                                          remove_duplicates(Rest,NewRest).
                             /* If not duplicated, then copy */
remove_duplicates([Item|Rest],[Item|NewRest]):- remove_duplicates(Rest,NewRest).

/* 'intersection' return true if one of the keywords was found among the */
/* words typed in.  From C&M page 154 */
intersection([],X,[]).
intersection([X|R],Y,[X|Z]) :- member(X,Y), !, intersection(R,Y,Z).
intersection([X|R],Y,Z) :- intersection(R,Y,Z).

/*>> 'irandom' returns a integer in the range specified by the first two <<*/
/*>> arguments to the predicate, E. Lagache, Ver-1.0, 3/88               <<*/
/*>> Values for computation taken from the first edition of "Oh Pascal"  <<*/
/*>> By Clancy and Cooper (page-227).                                    <<*/
irandom(Lower,Upper,Number) :- get_seed(Seed),
                               Start is (25173*Seed + 13849) mod 65536,
                               Number is (Start mod (Upper - Lower)) + Lower.

/* 'get_seed' will in general be an implementation specific predicate.     */
/* For ADA PROLOG, 'get_seed' will return the number of logical inferences */
/* so far made, using the ADA specific 'licount' predicate                 */
get_seed(Seed) :- licount(Seed).



/*>>---------------------------------------------------------------------<<*/
/*>> 'read_sentence' is a routine to take user input and make a list of  <<*/
/*>> atoms out of it.  It is slightly modified from Clocksin & Mellish   <<*/
/*>> page 104.                                                           <<*/
read_sentence([W|Wa]) :- get0(C), readword(C,W,C1), restsent(W,C1,Wa).

/* Given a word and the character after it, read in the rest of the sentence */
restsent(W,_,[]) :- lastword(W),!.

restsent(W,C,[W1|Wa]) :- readword(C,W1,C1), restsent(W1,C1,Wa).

/* Read in a single word, given initial character, and remembering what */
/* character came after that word.                                      */
readword(C,W,C1) :- single_character(C), !, name(W,[C]), get0(C1).

readword(C,W,C2) :- in_word(C,NewC), !, get0(C1), restword(C1,Cs,C2),
                    name(W,[NewC|Cs]).

readword(C,W,C2) :- get0(C1), readword(C1,W,C2).

/* continue process of stringing characters of the same word together */
restword(C,[NewC|Cs],C2) :- in_word(C,NewC), !, get0(C1), restword(C1,Cs,C2).

restword(C,[],C).

/*  These characters form words on their own */
single_character(44).        /* , */
single_character(59).        /* ; */
single_character(58).        /* : */
single_character(63).        /* ? */
single_character(33).        /* ! */
single_character(46).        /* . */

/* These characters can appear within a word */
/* the second in_word clause converts letters to lower case */
in_word(C,C) :- C>96, C<123.                /* 'a' to 'z' */
in_word(C,L) :- C>64, C<91, L is C+32.      /* 'a' to 'z' */
in_word(C,C) :- C>47, C<58.                 /* '0' to '9' */
in_word(39,39).                             /* '\'' */
in_word(45,45).                             /* '-' */

/* These words terminate a sentence */
lastword('.').
lastword('!').
lastword('?').

/*>>-----------------------------------------------------------------------<<*/

/*>> 'word_class' and 'default_responses' contain the text that will be    <<*/
/*>> presented to the user.  'word_class' also contains the list of        <<*/
/*>> keywords, that will be used to decide if this type of response is     <<*/
/*>> appropriate.                                                          <<*/

/* --------------------- Programming specific keywords -------------------- */
/* Words related to failure to get the file to consult properly */
word_class([consult,consulting,compile,compiling,load,loads,loading],
           [
              ['Do',you,know,at,what,location,the,problem,'is?'],
              ['Could',the,problem,be,at,a,different,place,from,where,the,
               error,message,is,'reported?'
              ],
              ['What',sort,of,diagnostic,message,did,the,system,'give?'],
              ['What',sort,of,problems,could,have,caused,this,'situation?'],
              ['Is',there,another,way,you,could,arrange,your,file,that,might,
               make,it,easier,to,find,the,'problem?'],
           ]
          ).

/* Problems with incorrect output */
word_class([output,print,prints,printing,write,writes,writing,printout],
           [
              ['What',sort,of,output,were,you,'expecting?'],
              ['What',kind,of,output,did,you,actually,get,'(if','anything)?'],
              ['How',could,you,modify,your,program,to,get,more,information,
               about,this,'i/o','problem?'
              ],
              ['Can',you,see,where,in,the,program,the,bug,must,be,'located?'],
              ['How',could,you,further,localize,the,source,of,the,incorrect,
               'output?'
              ]
           ]
          ).

/* Input problems */
word_class([input,read,reads,reading],
           [
              ['How',do,you,that,the,problem,is,caused,by,incorrect,input,
               'routines?'
              ],
              ['How',could,you,modify,your,program,to,get,more,information,
               about,this,'i/o','problem?'
              ],
              ['How',could,you,further,localize,the,source,of,the,incorrect,
               input,'behavior?'
              ],
              ['How',could,you,test,these,input,routines,in,'isolation?'],
           ]
          ).

/* flow of control problems */
word_class([infinite,loop,recursion,stepping,trace,tracing],
           [
              ['Where',is,the,last,place,that,you,know,your,program,was,running,
               'correctly?'
              ],
              ['How',do,you,know,that,the,program,is,not,behaving,as,it,
               'should?'
              ],
              ['Which',predicates,could,have,caused,this,'phenomenon?'],
              ['Is',there,any,way,that,you,could,isolate,the,predicates,that,
               are,at,'fault?'
              ],
           ]
         ).
/* Error word */
word_class([error,warning,failure,diagnostics],
           [
              ['Can',you,isolate,the,error,to,one,'place?'],
              ['Can',you,find,a,reasonable,interpretation,for,these,
               diagnostics
              ],
              ['Have',you,encountered,similar,sorts,of,messages,in,the,
               'past?'
              ],
              ['What',sort,of,information,would,allow,you,to,deal,with,this,
               'message?'
              ],
           ]
          ).

/* Logical errors */
word_class([infer,inference,deduce,deduction,entails,entailment],
           [
              ['What',should,have,the,system,'deduced?'],
              ['What',was,the,last,inference,that,you,know,was,'correct?'],
              ['How',do,you,know,that,the,inference,was,in,fact,incorrect,
               '(given',the,systems,actual,'configuration)?'
              ],
              ['What',sort,of,database,condition,could,have,caused,the,
               observed,'deductions?'
              ]
           ]
          ).

/* Bug talk */
word_class([bug,malfunction,wrong,incorrect,incomplete,unexpected],
           [
              ['How',do,you,know,you,have,a,'bug?'],
              ['Where',is,the,last,place,that,you,know,your,program,was,
               functioning,'correctly?'
              ],
              ['What',program,behavior,where,you,'expecting?'],
              ['What',indicates,that,something,is,'wrong?'],
              ['What',occurred,that,was,not,'expected?'],
              ['What',information,would,you,need,to,isolate,the,'bug?'],
              ['what',would,you,need,to,know,to,locate,the,'malfunction?'],
              ['What',tests,could,you,perform,to,get,at,the,'problem?'],
           ]
          ).

/* -----------------  Problem solving keywords  ------------------------- */
/* Alternatives */
word_class([option,options,alternatives,possible,possibilities],
           [
              ['What',alternatives,have,you,already,'tried?'],
              ['Are',there,other,possibilities,that,you,might,'consider?'],
              ['Which',options,have,you,already,'tried?'],
              ['Might','I',suggest,that,you,take,a,new,look,at,your,
               'alternatives.'
              ],
           ]
          ).
/* Reflection, on previous work */
word_class([tried,attempted,thought],
           [
              ['What',have,you,done,in,the,past,in,such,'situations?'],
              ['Tell',me,which,approaches,you,have,already,'tried?'],
              ['What',have,you,attempted,'previously?'],
              ['What',have,you,done,here,that,you,might,want,to,do,differently,
               in,the,'future?'
              ]
           ]
          ).

/* Strategic problem solving, evaluating plans */
word_class([try,attempt,do,complete,investigate,think,thinking],
           [
              ['How',will,trying,this,help,you,out,of,your,'impasse?'],
              ['What',can,you,learn,from,doing,'this?'],
              ['Are',you,sure,that,there,is,not,a,more,productive,investigation,
               that,you,could,'make?'
              ],
              ['Are',there,better,ways,to,get,the,information,you,need,to,solve,
               this,'problem?'
              ],
           ]
          ).

/* -------------------------- Human Psychology words ----------------------- */
/* stuck words */
word_class([stuck,stopped,impasse],
           [
              ['Perhaps',you,should,reflect,back,on,the,various,'possibilities.'
              ],
              ['There',must,be,alternatives,that,you,have,not,'considered.'],
              ['I',suggest,that,you,step,back,from,the,problem,and,review,
               what,you,have,'tried.'
              ],
           ]
          ).
/* "down" words */
word_class([depress,depressing,depressed,frustrating,frustrated,mad,annoy,
            annoyed,annoying
           ],
           [
              ['It',is,not,a,good,idea,to,get,worked,up,about,a,'program.'],
              ['One',should,not,take,this,too,'seriously,',after,all,it,is,
               only,a,'program.'
              ],
              ['If',this,task,is,getting,to,you,perhaps,you,should,take,a,break,
               and,come,back,to,it,'later.'
              ],
              ['Perhaps',you,have,been,working,too,long,on,this,one,'problem,',
               maybe,you,should,take,a,'break.'
              ],
              ['Do',you,tell,me,that,this,program,is,getting,to,'you!'],
              ['Well',nobody,said,that,programming,was,'easy.'],
              ['Do',not,get,worked,up,over,'this,','after,all,',no,program,that,
               is,interesting,is,easy,to,'write.'
              ]
           ]
         ).

/* "Bad" words (should this sort of thing be censored!?!) */
word_class([fuck,fucking,shit,shitty,damn,screw,screwed,hell],
           [
              ['Well','I',hope,that,relieves,your,'aggressions;',now,can,
               we,get,back,to,'work?'
              ],
              ['I',am,glad,you,know,'profanity;',unfortunately,this,system,
               only,understands,'PROLOG!'
              ],
              ['Yes,','yes,',profanity,is,the,language,that,all,programmers,
               know,'best!'
              ],
              ['If',you,can,not,say,anything,more,'constructive,',perhaps,
               you,should,take,a,break,and,come,back,to,this,'problem.'
              ],
              ['Sorry',that,language,is,not,in,my,'vocabulary!'],
           ]
         ).

/*  Help words */
word_class([help,assistance,explain,explanation],
           [
              ['In',what,area,do,you,need,some,'assistance?'],
              ['Can',you,be,more,specific,about,what,sort,of,help,you,'need?'],
              ['Exactly',what,sort,of,information,do,you,'seek?'],
              ['In',what,way,may,'I',be,of,'assistance?'],
              ['What',kind,of,advice,do,you,'need?'],
              ['Exactly',in,what,area,do,you,need,an,'explanation?'],
              ['Please',tell,me,background,about,your,'problem?'],
              ['Could',you,further,elaborate,on,the,type,of,problem,you,are,
               'having? '
              ]
           ]
          ).

default_responses([
                   ['Please','continue.'],
                   ['Could','you','say','more','about','your','problem.'],
                   ['I','would','like','to','hear','some','more','specifics.'],
                   ['Could','you','please','elaborate','on','one','aspect',
                    'of','your','problem.'
                   ],
                   ['Is',there,anything,else,that,you,know,about,this,
                    'problem?'
                   ],
                   ['I',do,not,quite,understand,the,'situation;',could,you,
                    elaborate,it,for,'me?'
                   ]
                  ]
                 ).

/* * * * * * * * * * * * * * * * * * * * * * * */
/*  'nthelem' returns the element in the       */
/*  'Index' place of the list.                 */
/*                                             */
/*     E. Lagache,  Vers. - 1.00, Dec - 86     */
/* * * * * * * * * * * * * * * * * * * * * * * */
nthelem([],_,error):- !, fail.  /* fail if list is smaller than index */
nthelem([Item|_],1,Item):- !.   /* return item */
nthelem([X|Rest],NewIndex,Item):- Index is NewIndex-1,nthelem(Rest,Index,Item).

/* end file consulta.pro */

------------------------------

Date: 24 Mar 88 02:37:00 GMT
From: quintus!ok@unix.sri.com  (Richard A. O'Keefe)
Subject:  An Eliza-like problem solving assistant (400+ lines).

In article <7845@agate.BERKELEY.EDU>,
lagache@violet.berkeley.edu (Edouard Lagache) distributed
an "Eliza-like problem solving assistant".

(1) In the tables at the end of the program, the pattern
	word_class([...],
	    [
		[...],
		...
		[...],
*--------------------^
	    ]).
    occurs quite often.  While C allows extra commas in initialisers,
    many Prolog systems will be unhappy about that extra comma.

(2) In order to test whether any of a given list of Keywords occurs in
    a given Sentence, the program does

	intersection(Keywords, Sentence, List),
	List \== [],

    This is correct, but there isn't a lot of point in constructing List.
    A more efficient approach (effiency is not a concern in this program)
    would be to call

	intersect(Keywords, Sentence)

    where for example

	intersect(Set1, Set2) :-
		member(X, Set1),
		member(X, Set2),
		!.

(3) I thought I'd try the program.  This is what I got:
Please describe your problem.  Type 'quit.' to resume work.
e> My nematodes have been eaten by the peripatus.
Could you say more about your problem. 
e> Yes.
Could you please elaborate on one aspect of your problem. 
e> Well, the peripatus crawled out of its box last night, and it got into
e> another box on the same bench, where we keep nematodes, and well, it
e> ate the lot of them.
Is there anything else that you know about this problem? 
e> I suppose there are two problems, really.  One problem is how do I
e> stop this sort of thing in the future, and the other is where do I
e> get some more nematodes right now.  I want your help with the second
e> part of the problem.
What can you learn from doing this? 
e> From doing WHAT?
Could you say more about your problem. 
e> I just told you everything there was to say.
Could you say more about your problem. 
e> You're getting a bit repetitious, aren't you?
I do not quite understand the situation; could you elaborate it for me? 
e> Gods below, what is there to understand?  I need some nematodes, I
e> had some nematodes, but Hodgkins' wretched peripatus ate them.
Is there anything else that you know about this problem? 
e> Oh forget it.
Could you say more about your problem. 
e> quit.

    In case you were wondering, the e> lines do make sense.

(4) Part of the reason for the frustrating and unhelpful nature of the
    conversation shown is that the program is not Eliza-like.  One of
    the things that Eliza would do is pick up phrases of yours and
    throw them back at you.  For example, after my third input, an
    Eliza-like program might say
	Tell me more about the box.
    			   ^^^^^^^----- copied from input
    or after the last input but two,
	Why did Hodgkins' wretched peripatus eat them?
		^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ transformed input
------------------------------

End of PROLOG Digest
********************