Subject: Re: Idea: [] != '[]'?

From: Jan Wielemaker <[email-masked]>
Date: Wed, 17 May 2000 09:47:18 +0200

On Wed, 17 May 2000, Richard A. O'Keefe wrote:
>He pointed at the ambiguity that [] is both an atom and the
>	empty list.
>
>We have known that since 1961 (hint:  Prolog copied that from Lisp).
>We've known how to program with that in mind since 1961 too.
>
>	I've come across this various times, as I also sometimes
>	come acress foo == foo().
>
>Some non-Edinburgh-compatible systems make this distinction too,
>and allow foo() as syntax for a term that is really {foo} underneath.
>I have never understood the point.

With {foo} you mean {}(foo) or the atom 'foo'?  One argument for
foo() to me is consistency.  It is consistent for (especially
non-prolog) programs generating Prolog source and it can improve
readability.

>Yes, well, what you have there is a badly broken data structure design.
>Why break the language when you can fix the data structure design?
>
>	doit(word(Text)) :- ...
>	doit(foo) :- ...
>
>See?  You don't even need the cut if you do it right!

I agree, but there are two reasons why I don't like this is *sometimes*.
If I have to type the structures I much more like writing

	doit([ 'Hello World', foo(), ... ]).
than
	doit([text('Hello World'), foo, ...]).

especially if there is a lot of text to type.  Of course I can write
the text in XML/SGML and parse it, which is probably the best solution.

Second reason is sometimes space.  word(hello) takes 3 words, where
'hello' only takes one (assuming the atom is shared often enough).
We lately have a hobby of processing big documents and a serious
reduction of the stacks is therefore welcome.

>	* [] != '[]'
>	===========
>	
>	Both can be cured, extending SWI-Prolog.
>
>It's not a disease.  It's not an accident.  It's not a mistake.
>Neither of these points *NEEDS* changing, they are fine the way they are.
>
>	First let us consider the
>	empty list.  This is an odd atom (and it is odd that the empty list,
>	which is a list after all is also an atom).
>
>It is not the only one.

I know, but it is the most anoying one :-)

>		* It is returned by reading [], [ ], [/*hello*/]
>		* It is written as [] (note that without precautions in
>		  write/1 it is written as '[]').
>		* It does *not* unify with '[]'
>	
>If you've ever done anything with nonstandard logics in Prolog,
>you've probably tried using
>	<>(Formula)
>	[](Formula)
>I know I have.  It would be a sad day if this broke.

This is a good point to avoid the next step: turning [] into a non-atom.
It is not if we do just the above: [] is still and atom.  It just isn't
the same atom as '[]'.  So [](Formula) is still a valid term, but

	[](F) == '[]'(F)

fails.  Thats not really unreasonable, is it?

>	We can even go further:
>	
>		* atom/1 fails on it.  Just is_list/1 succeeds.
>		* atom_chars/codes, etc. raise an exception on it:
>		  it has no character representation.

Your example (and the comments by Lutz) clearly indicate [] should
remain an atom.  So this part is surely off.

>		* Code explicitly using '[]' as an empty-list will fail.
>		  Does such code exist?
>	
>Yes.  Hint:  quite a bit of Prolog code is written by other programs,
>not typed in by hand.

It is quite unlikely a program generator will generate quoted '[]' if
it means the empty list.

>		* Foreign code doing PL_new_atom("[]") to get access to
>		  the empty list will fail.  The interface already defines
>		  PL_put_nil(), PL_unify_nil(), etc.  This appears
>		  acceptable.
>	
>You have forgotten a HUGE amount of code which relies (sometimes
>indirectly) on the term data structure I've mentioned before.
>You have forgotten code which relies on [] being an atom, and therefore
>usable as a function symbol and an operator.
>You have forgotten code which tests for end-of-list using atom(List).
>You have forgotten code which does
>
>	is_callable(Term) :-
>	    nonvar(Term),
>	    functor(Term, Symbol, _),
>	    atom(Symbol).

So with [] \== '[]', but still an atom, this just works right.

>(In fact I expected to be able to use []/0 for my own purposes,
> and was rather surprised at the following SWI Prolog interaction:
>	?- [].
>
>	Yes

This is consistency with ?- [load].   Dunno about Quintus (my license
has expired), but sicstus does the same.

> Oh, is there any way to eliminate that irritating blank line
> before the answer?)

:- multifile
	prolog:message/3.

prolog:message(query(yes)) -->
	[ 'Yes' ].

>	* Introducing foo()
>	
>	I.e. compounds without arguments.  Basically this just means making
>	read/1 not check for it: internally these things already exist.
>
>In other Prologs they do not.  You are talking about making fundamental
>aspects of SWI Prolog incompatible with ISO Prolog and many real Prologs.
>It is a wholly unnecessary *COMPLICATION* of the language.

I agree this is the case if it poses incompatibilities.  If it does not,
it is just one of these goodies implementors add to their language. 
Like some Prologs allowing for Var(a), gcc allowing for automatic
arrays whose length is defined by a variable, allowing for 0-length
arrays, etc.

Sometimes such additions become so popular they reach the standard, in
other cases users can choose between comfort and portability.

The only problem I see with foo() are functor/3 and =../2.  For the rest
you can use it or leave it.

>Let's see one or two (one to two page) examples of code that would
>benefit from these changes, and let's see how much better the code
>is when rewritten so it doesn't have any use for them.

Basically it all boils down to using Prolog in mapping huge sequences
of mixed text (as atoms) and actions (macros, ...).  Cleanest way to
write such systems is to use text(Text) for text and other terms for
actions as well as using difference-lists (grammar rules) to expand
actions.

Space efficiency make using plain text-as-atoms attractive and in some
cases lists-of-lists as oposed to a nice flat list constructed with
difference lists sometimes makes life easier (and sometimes faster).

If you can get these without breaking real-life code (i.e. not
constructed counter examples), I think it is worth it.

>We'd all be much better off if time were spent improving SWI Prolog's
>performance rather than breaking working code by adding misfeatures
>it is better off without.

Well, I don't want flame-wars.  The code is GPL, so you can stick in
a better engine if you want.  For most of our purposes the current
engine does a fairly good job.  Sometimes it is improved a bit
(e.g. choice-point handling in 3.3.6), but most of the emphasis is
on enabling it to do the things we need it to do.

For now, it has  to be able to handle RDF-models holding about 3e6
triples.  This takes too long to load and requires too much memory. 
These are the things that have always guided the development of
SWI-Prolog.

	Regards --- Jan