[comp.lang.prolog] logic programs -> procedural lang?

arman@oahu.cs.ucla.edu (Arman Bostani) (09/22/89)

I am looking references to any work done in the area of "compiling"
logic programming languages (i.e. Prolog, CLP(R), etc.) into a
procedural/deterministic language such as C.

I, myself, have written a compiler from LOG(F) (functional programming
language, related to prolog) to a variant of C, but I have seen very
little published work in this area. 

Thanks for the help,
-arman.

-- Arman Bostani	// UCLA Computer Science Department
-- arman@CS.UCLA.EDU	// ...!(ucbvax,rutgers)!ucla-cs!arman

bradley@cs.utexas.edu (Bradley L. Richards) (09/23/89)

As far as I'm aware, little work *has* been done in this area (although
Borland's highly successful Turbo Prolog is compiled to machine code).  One
big reason, at least with Prolog, that little work has been done is that
you almost inevitably sacrifice one of the most important and distinctive
features of the language when you compile it:  the ability to have a program
change its universe while running (assert/retract).

Brad

ok@cs.mu.oz.au (Richard O'Keefe) (09/23/89)

In article <869@gamera.cs.utexas.edu>, bradley@cs.utexas.edu (Bradley L. Richards) writes:
> As far as I'm aware, little work *has* been done in this area

The first paper I saw on the subject was Chris Mellish's paper about
the Prolog component of PopLog.  I've seen several others since (alas,
my library is in two other countries at the moment, so no reference)
and they mostly follow his approach.  Ignoring arguments,

	p :-
		built-in-test.
	p :-
		q.
	p :-
		r, s.

is compiled as a function with a continuation argument:  if it succeeds
it calls its continuation; if it fails it returns.

	define p(Continuation);
	    if built-in-test then
		call(Continuation);
	    endif;
	    q(Continuation);
	    r(lambda (). s(Continuation endlambda);
	    ;; fail by returning
	enddefine;

The top-level predicate is called with a continuation which prints
the variable bindings and then either returns (if the user types ";")
or longjumps all the way out (if the user types <CR>).  I don't
remember how cuts are handled.  In a language like C which doesn't
let you construct closures (lambda ... endlambda) you can get the
same effect by pushing information on a "continuation stack".

There are actually some similarities between this method and David
Warren's "total non-structure-sharing".

axaris@cs.buffalo.edu (Vassilios Axaris) (09/25/89)

Hello,

I have been surprized when I first got my Turbo Prolog compiler, in that I was
required to specify the type of objects being used. Later, I realized that even
though this was putting a burden on the programmer, as well as deviating from
the standard, it could be (as it was I believe) useful in minimizing the runtime
type checking of the objects, in Common Lisp manner. In today's RISC world, I
think it would be very useful to include such declarations to aid the compiler
in creating efficient code, by minimizing tag processing. 
How does the Prolog community feel about such an addition? Is it reasonable to 
do it for the sake of improved execution speed on workstation type environments?

Vassilios E. Axaris
SUNY/Buffalo Computer Engineering

ok@cs.mu.oz.au (Richard O'Keefe) (09/25/89)

In article <10822@eerie.acsu.Buffalo.EDU>, axaris@cs.buffalo.edu (Vassilios Axaris) writes:
> I have been surprized when I first got my Turbo Prolog compiler, in that I was
> required to specify the type of objects being used.

In short, you were surprised to discover that what you got was NOT a
Prolog compiler, but a compiler for another (closely related, but still
OTHER) language.

Whenever I hear that someone is thinking of getting Turbo Prolog, I tell
them to look first at Trilogy.  If you are willing to use a sort of
Prolog/Pascal hybrid (Turbo Prolog), you ought to be happy with a logic
programming language which is not a Prolog/Pascal hybrid but was designed
from the start to let you do the kinds of things that Pascal is good for
in a clean logic programming way.  I have a copy of Trilogy, and while
it's somewhere between two other countries at the moment, I was favourably
impressed by it, and would prefer Trilogy to Turbo any day of the week.

> Later, I realized that even
> though this was putting a burden on the programmer, as well as deviating from
> the standard, it could be (as it was I believe) useful in minimizing the runtime
> type checking of the objects, in Common Lisp manner.

You should be aware that there are Prolog systems for the PC which can
run rings around Turbo Prolog, *without* sacrificing compatibility.  I'll
let the vendors tell you which ones.

Basically, "run time type checking" is a red herring for Prolog.
Consider something like
	append([], L, L).
	append([H|T], L, [H|R]) :-
		append(T, L, R).
In Pascal terms, this would be
	type
	    listPtr = ^listRrec;
	    listTag = (kNil, kCons);
	    listRec = record case tag: listTag of
			kNil: ();
			kCons: (head: something; tail: listPtr);
		      end {listRec};

	function append(A, Z: listPtr): listPtr;
	    begin
		case A^.tag of
		    kNil:	append := Z;
		    kCons:	append := mkCons(A^.head,
						 append(A^.tail, L));
		end {case};
	    end {append};

The 'case' statement in the Pascal program is the equivalent of the
'indexing' done in Prolog.  No amount of type checking at compile time
is going to eliminate that 'case' statement.  But that's where the
"run-time type checking" is happening in the Prolog system.

To be sure, tagging does slow arithmetic down.  Static typing can help
there, *IF* you also have strict mode checking as well.  However, if
arithmetic is more than say 30% of the cost of your Prolog program,
you aren't doing things the Prolog Way.

Lisp needs types much worse than Prolog, because the Lisp equivalent
of append/3 would be
	(defun app (A Z)
	    (if (endp A)			; check A
		Z
		(cons (car A)			; check A again
		      (app (cdr A)		; check A again
			   Z))))    
where A gets checked three times.  In the code produced by a good Prolog
compiler, this effectively happens just once, and is ``paid for'' by the
`if'.  See
    Author:  David H.D. Warren, Luis M. Pereira
    Title:   Prolog: the language and its implementation compared with Lisp 
    Journal: Proceedings of the Symposium on Artificial Intelligence
	     and Programming Languages
    City:    University of Rochester
    Date:    August 1977
    Pages:   109-115
    Other:   published as SIGPLAN Notices 12:8 and as SIGART Newsletter 64

> In today's RISC world, I
> think it would be very useful to include such declarations to aid the compiler
> in creating efficient code, by minimizing tag processing. 

Hang on a minute, Turbo Prolog runs on 80*86s, which aren't RISCs...

Real Prologs (as opposed to Turbo[*] Prologs) let you pass variables around
in a way which requires run-time tests ANYWAY in order to tell whether a
variable is instantiated or not; given that, any other tag checking that
may be required comes free.  Advanced Prologs (SICStus Prolog, NU Prolog,
I believe ECRC though I haven't tried it, CHIP, CLP(-)) allow variables
to be ``constrained'', which also requires run-time checks in the course
of which other tag checks come free.

[*] ``Turbo'' is a Latin word meaning ``I swirl [things] around,
make [things] confused.''  A ``turba'' is a mob.

> How does the Prolog community feel about such an addition? Is it reasonable to 
> do it for the sake of improved execution speed on workstation type environments?

Today's good Prolog compilers on today's workstations already produce fast
code, to the point where you might write C or Fortran code for number-
crunching or interfacing to existing libraries, but would not be tempted to
rewrite your program as such in C.  (Unless you have written very bad Prolog
code.)  Don't make the mistake of thinking that types are necessary for
efficiency:  BCPL, BLISS, and many other systems programming languages are
not typed.

However, type checking *IS* useful for detecting mistakes in programs,
and types are useful when designing a program.  As far as I know,
Bruynooghe was the first to write about types in Prolog.  But there is
a large and growing literature on type checking and type inference in
logic programs.  The NU Prolog Debugging Environment (spelled NUDE,
apparently pronounced `nood') includes a rather powerful type checker.
The source code of the Mycroft & O'Keefe type checker was posted to this
news group a year or so ago.  [Sorry, playmates, but there is a mistake
in it.  It treats disjunctions as if they were conjunctions.  This
usually doesn't matter, but occasionally it will reject a disjunction
which is in fact well typed.]

picart@irisa.irisa.fr (Marc Picart) (09/25/89)

In article <10822@eerie.acsu.Buffalo.EDU>, axaris@cs.buffalo.edu (Vassilios Axaris) writes:
> 
> Hello,
> 
> I have been surprized when I first got my Turbo Prolog compiler, in that I was
> required to specify the type of objects being used. Later, I realized that even
> though this was putting a burden on the programmer, as well as deviating from
> the standard, it could be (as it was I believe) useful in minimizing the runtime
> type checking of the objects, in Common Lisp manner. In today's RISC world, I
> think it would be very useful to include such declarations to aid the compiler
> in creating efficient code, by minimizing tag processing. 
> How does the Prolog community feel about such an addition? Is it reasonable to 
> do it for the sake of improved execution speed on workstation type environments?
> 
> Vassilios E. Axaris


My opinion is that the compiler can infere a lot of the declarations 
by itself. (you can see the work of C. S. Mellish or S. K. Debray) 
I don't think that, in logic programming, it is necessary for the 
programmer to help the compiler.
The reason is that the aim with high level languages, such as Prolog, is
to separate the logic specification, which is the responsability of the 
programmer, from the implementation which is the responsability of
the compiler.


    Marc Picart.

david@indetech.com (David Kuder) (09/26/89)

In article <27335@shemp.CS.UCLA.EDU> arman@oahu.cs.ucla.edu (Arman Bostani) writes:
>I am looking references to any work done in the area of "compiling"
>logic programming languages (i.e. Prolog, CLP(R), etc.) into a
>procedural/deterministic language such as C.

I know of no references to such work.  I know of at least one system that
tried to compile.  I believe that many of the commercial Prolog vendors
do compilation.  BIM is perhaps the most thorough, but I'm sure Quintus
will correct me if I'm wrong.

In article <869@gamera.cs.utexas.edu> bradley@cs.utexas.edu (Bradley L. Richards) writes:
>As far as I'm aware, little work *has* been done in this area
>(although Borland's highly successful Turbo Prolog is compiled to
>machine code).

On soapbox, I say: Turbo Prolog isn't Prolog!  They decided to compile
by stripping the guts out of unification among other things.  Don't
consider them the typical case of compiling Prolog.

>One big reason, at least with Prolog, that little work has been done
>is that you almost inevitably sacrifice one of the most important and
>distinctive features of the language when you compile it: the ability
>to have a program change its universe while running (assert/retract).

Right.  Also there are the predicates that involve running other
predicates: call, setof, etc.  Since you can build an arbitrary
predicate to be run you need to compile in the interpreter.  So you
can solve the assert/retract by simply always interpreting those
clauses.  Or you can compile the compiler into every executable.
Turns out that assert and compile aren't necessarily all that
different in some implementations.  Still even with that savings
binaries are enormous.
-- 
David A. Kuder					david@indetech.com
415 438-2003	              {sun,sharkey,pacbell}!indetech!david

garym@ulysses.UUCP (Gary Murphy) (09/26/89)

There is one alternative half-way between a compiled and an 
interpreted form.  In SB-Prolog, the source files are 'compiled'
to a bytestream of instructions for the Warren Abstract Machine (WAM),
which allows SBP to store compact, pre-compiled and dynamically loaded
predicates.  Although not as fast as a true compiler, it performs
much better than a straight interpreter.

There is yet another alternative: wasn't there a posting a while ago
gloating over a prolog-based cpu?  That's the one _I_ want! :-)


-- 
     Gary Murphy - Cognos Incorporated - (613) 738-1338 x5537    
  3755 Riverside Dr - P.O. Box 9707 - Ottawa Ont - CANADA K1G 3N3
          e-mail: decvax!utzoo!dciem!nrcaer!cognos!garym         
  Cosmic Irreversibility: 1 pot T -> 1 pot P, 1 pot P /-> 1 pot T

lee@munnari.oz.au (Lee Naish) (09/27/89)

In article <1503@irisa.irisa.fr> picart@irisa.irisa.fr (Marc Picart) writes:
>to separate the logic specification, which is the responsability of the 
>programmer, from the implementation which is the responsability of
>the compiler.

I agree with Jose Alberto, that types can be part of the specification
(even if they are missing from the program).  For example, in the
natural specification of append, all arguments are lists.  This
information is missing in the program.  Check out the following
reference if you are interested (unfortunately it has some technical
errors - I'll produce a revised version some day hopefully).

%A Lee Naish
%T Specification = program + types
%J Proceedings of 7th Conference on Foundations of Software Technology
and Theoretical Computer Science
%C Pune, India
%D December, 1987
%O Published in LNCS 287 by Springer Verlag

I would also like to make some comments about Richard O'Keefe's remarks
concerning complexity.  Obviously complexity is an important issue.  It
is of vital importance when type checking is always done (eg, in a
strictly typed language or with a smart Prolog compiler which attempts
to infer types to improve efficiency).  However, if a type checker is
used simply as a programming aid to locate (some) bugs, then complexity
is less important.  It is possible to have a very useful debugging tool 
whose complexty is exponential in the worst case (the Mycroft O'Keefe
type checker is a case in point).

If I had a linear complexity type checker which failed to find the bug
in my program, I would certainly resort to a worst case non-linear
complexity type checker which might find the bug (even if I had to put
the job in background, and maybe kill it when the paging on my Sun 3/50
got too bad:-).  The great thing about finding bugs by static analysis
is that no programmer intervention is required.

	lee

micha@ecrcvax.UUCP (Micha Meier) (09/27/89)

In article <27335@shemp.CS.UCLA.EDU> arman@oahu.cs.ucla.edu (Arman Bostani) writes:
>
>I am looking references to any work done in the area of "compiling"
>logic programming languages (i.e. Prolog, CLP(R), etc.) into a
>procedural/deterministic language such as C.

There is an article "A Piggy-back Compiler For Prolog" by J.L.Weiner and
S.Ramakrishnan in SIGPLAN'88 about a Prolog compiler that compiles
into C. The authors claim that they got reasonable performance
and portability. Since I've done similar work with ECRC-Prolog,
I can say that a Prolog compiler that generates C is extremely
user-unfriendly and can never achieve the speed of a good WAM emulator
without serious portability flaws. There has been another note
about a Prolog compiler into C, Proteus Prolog from MCC,
where a very high speed was obtained with some slight modifications
in the C compiler.

Our experience with generating C was interesting in that it showed
us that it is not the way to go, although it has some advantages.
Shortly, the main problems vere space and time :-). The compiler either
generates huge amounts of C code (if every WAM instruction is expanded)
or it uses some sort of threaded code or subroutine calls which both
need some code in assembler or modifications in the C compiler
if they have to be efficient. This actually loses the portability
leaving no other major advantage. Compilation time was the other main
problem; if the compiler is written in Prolog, it is slow enough,
but it is still nothing compared to the speed of the C compilation.
The point is that there is much unnecessary work done in the C compiler,
because the Prolog compiler generates only a very small subset of C,
the same holds for the assembly code generated by the C compiler.

The 'normal' approach, i.e. Prolog compiler generating abstract WAM code
and possibly a native code back-end generator achieve much better
(orders of magnitude) compilation speed. For example, with our current
system, SEPIA, we can compile programs about 1000 times faster than with
ECRC-Prolog and the speed of the generated code is better in SEPIA.

If the aim is just to compile a Prolog program into an equivalent (and readable)
C program, it is a different matter which, I think, can be theoretically
achieved. The main task is to implement the backtracking
which can be done in the Poplog way, or using continuations in the WAM way,
(i.e. either return on success or return on failure),
however such a program cannot achieve performances comparable with
the up-to-date Prolog systems.

--Micha

debray@arizona.edu (Saumya K. Debray) (09/27/89)

arman@oahu.cs.ucla.edu (Arman Bostani) writes:

> I am looking references to any work done in the area of "compiling"
> logic programming languages (i.e. Prolog, CLP(R), etc.) into a
> procedural/deterministic language such as C.

See D. H. D. Warren's original work on compiling Prolog:
"Implementing Prolog -- compiling predicate logic programs",
DAI Research Reports 39 and 40, U. Edinburgh, May 1977.  [This
is hard to get from Edinburgh, but I've heard that it's available
as a research report from SRI International.]

There's a bunch of papers on implementing Prolog in Lisp, e.g.
see the paper by Ken Kahn and Mats Carlsson in "Implementations of
Prolog", ed. J. A. Campbell, Ellis Horwood, 1984.

Andrew Turk discusses a number of optimizatios for native code
Prolog compilers in Proc. ICLP 86.  Mike Newton discusses compiling
Prolog into native code for an IBM-3090 in "A High Performance
Implementation of Prolog", Caltech CS Dept. Tech. Report TR:5234:86,
Apr. 1987.

There is also a paper in SIGPLAN-88, by Weiner and Ramakrishnan,
that discusses compilation to C.  See SIGPLAN Notices vol. 23 no. 7,
July 1988.  [This paper makes rather strong assumptions about
the program, e.g. about the availability of type information, and
hence may not satisfy purists.]

There is at least one "real" Prolog implementation I'm aware of
that compile to native code: BIM-Prolog, from Belgium; I believe
Sicstus Prolog, from Sweden, also has a native code compiler for
68020-based machines.

bradley@cs.utexas.edu (Bradley L. Richards) writes:

> As far as I'm aware, little work *has* been done in this area (although
> Borland's highly successful Turbo Prolog is compiled to machine code).  One
> big reason, at least with Prolog, that little work has been done is that
> you almost inevitably sacrifice one of the most important and distinctive
> features of the language when you compile it:  the ability to have a program
> change its universe while running (assert/retract).

Not really, it's possible to mix compiled and interpreted code.

-- 
Saumya Debray		CS Department, University of Arizona, Tucson

     internet:   debray@arizona.edu
     uucp:       arizona!debray

jwmills@iuvax.cs.indiana.edu (Jonathan Mills) (09/28/89)

In article <7152@ulysses.UUCP> garym@cognos.UUCP (Gary Murphy) writes:
>
>There is yet another alternative: wasn't there a posting a while ago
>gloating over a prolog-based cpu?  That's the one _I_ want! :-)
>

If it's the LIBRA, we're working on it.  The VLSI prototype of the datapath
unit is due back from MOSIS by October 2nd, and we will be testing it in
both a pipelined & non-pipelined mode.  If it works, the next step will be
to put 10 slices on a chip to get tag, garbage collect & value ALUs on 4
chips.

We are also experimenting with an automatically derived version of the
LIBRA using Steven D. Johnson's Digital Design Derivation system (DDD).
Although DDD cannot yet handle pipelined architectures, it has the benefit
of producing designs that are correct with respect to their original
specification.

Finally, in my dissertation I described a clause compiler that emitted
opcodes for an early version of the LIBRA, and which did NOT post-process
WAM code, but instead built a DAG attributed with properties of each token
in the Prolog clause, "head/body", "nesting level", "<type>".  WAM code
could easily have been output from this structure, but there was no need,
particularly since I was interested in generating RISC opcodes.

Jonathan Wayne Mills	(812) 331-8533/855-7081

jwmills@iuvax.cs.indiana.edu (Jonathan Mills) (09/28/89)

In article <14299@megaron.arizona.edu> debray@arizona.edu (Saumya K. Debray) writes:
>
>... it's possible to mix compiled and interpreted code.
>

It is also possible to implement assert & retract as demons that fill in
and link (or unlink) code templates. See the paper by Mills & Buettner in
ICLP 88. Specializations of this kind are closely related to the general
topic of partial evaluation.  The notion of deriving the demon by compiling
the clause template is similar to the notion of partially evaluating a
partially evaluated program to yield a generator of specialized programs.

Jonathan Wayne Mills	(812) 331-8533/855-7081

jeff@aiai.ed.ac.uk (Jeff Dalton) (10/04/89)

In article <2181@munnari.oz.au> ok@cs.mu.oz.au (Richard O'Keefe) writes:
>Lisp needs types much worse than Prolog, because the Lisp equivalent
>of append/3 would be
>	(defun app (A Z)
>	    (if (endp A)			; check A
>		Z
>		(cons (car A)			; check A again
>		      (app (cdr A)		; check A again
>			   Z))))    
>where A gets checked three times.  In the code produced by a good Prolog
>compiler, this effectively happens just once, and is ``paid for'' by the
>`if'. 

Richard, I've seen this claim before (in Warren's paper, for example),
and I've always been a bit puzzled by it.  I would expect compiled
Lisp code to make only one check, not three.  And indeed, if I try
various Lisps where it's easy for me to read the compiled code
(such as Franz Lisp or KCL), it's clear that only one check is made.

However, in many Lisps there's only one check because the compiled
code for a car or cdr never includes a check.  That is, while some
Lisps might analyse the code to see whether a acheck might be 
needed, some certainly don't: they just emit the code to extract
the car or cdr, with no check.

It's fair to flame Lisp, or at least some Lisp implementations,
for being less safe.  It may even be fair to say Lisp needs types
more than Prolog does.  But I don't think it's fair to say Lisp
makes three checks, because it doesn't.

-- Jeff

ok@cs.mu.oz.au (Richard O'Keefe) (10/10/89)

> In article <2181@munnari.oz.au> ok@cs.mu.oz.au I claimed that
> (defun app (A Z) (if (endp A) Z (cons (car A) (app (cdr A) Z))))    
would check three times that A is a list.

In article <979@skye.ed.ac.uk>, jeff@aiai.ed.ac.uk (Jeff Dalton) writes:
> Richard, I've seen this claim before (in Warren's paper, for example),
> and I've always been a bit puzzled by it.

Why be puzzled by it?  David Warren and I were both used to Lisp systems
(in my case Interlisp-D) that do in fact make the check that many times.
Admittedly, Interlisp-D does the check in microcode, but then the Prolog
equivalent is in microcode on the Xerox Lisp machines too.  People at
RMIT in Melbourne use Common Lisp on MacIvory, and I would be surprised
if that Lisp system didn't repeat the check three times as part of the
three instructions involved.  The Lisp system I use here from time to
time definitely has the check repeated in CAR and CDR -- I just checked.
(ok, ok, so it's a Scheme, not a Lisp, big deal.)

> I would expect compiled Lisp code to make only one check, not three.

I'll get back to this shortly.

> However, in many Lisps there's only one check because the compiled
> code for a car or cdr never includes a check.  It's fair to flame Lisp,
> or at least some Lisp implementations, for being less safe.

Now that is a serious mistake.  Consider those broken Lisp implementations
(but not the ones I've used or the one David Warren used) duly flamed.

> But I don't think it's fair to say Lisp makes three checks,
> because it doesn't.

It _was_ fair for me to say that, because every Lisp I'd personally checked
DOES make the three checks.

Back to the question of what compiled Lisp code would do.  A good Lisp
compiler would exploit any type information it could pick up along the way.
Now (endp A) succeeds if A is NIL, fails if A is a CONS, and is supposed to
signal an error otherwise, so when we have (if (endp A) #|foo|# #|baz|#)
a smart compiler would know in #|foo|# that A was NIL and it would know in
#|baz|# that A was a CONS, so when it saw (car A) and (cdr A) it would know
that it didn't need to repeat the checks.  My own good habit of using (endp -)
rather than (null -) defeated my own argument here!  However, if I had
written (if (null A) #|foo|# #|baz|#) then the compiler would only have
been entitled to rely on A being different from NIL in the #|baz|# branch,
so the (car A) would have to perform the check, and the (cdr A) would then
be able to omit it.
					  "
So what I *should* have said is that "a naive Lisp compiler which makes
the checks which are necessary for safety will do more checking than a
  "
naive Prolog compiler which makes the checks which are necessary for safety".

jeff@aiai.ed.ac.uk (Jeff Dalton) (10/13/89)

In article <2367@munnari.oz.au> ok@cs.mu.oz.au (Richard O'Keefe) writes:
> In article <2181@munnari.oz.au> ok@cs.mu.oz.au I claimed that
> (defun app (A Z) (if (endp A) Z (cons (car A) (app (cdr A) Z))))    
> would check three times that A is a list.

>In article <979@skye.ed.ac.uk>, jeff@aiai.ed.ac.uk (Jeff Dalton) writes:
>> Richard, I've seen this claim before (in Warren's paper, for example),
>> and I've always been a bit puzzled by it.

>Why be puzzled by it?  David Warren and I were both used to Lisp systems
>(in my case Interlisp-D) that do in fact make the check that many times.
>Admittedly, Interlisp-D does the check in microcode, but then the Prolog
>equivalent is in microcode on the Xerox Lisp machines too.  People at
>RMIT in Melbourne use Common Lisp on MacIvory, and I would be surprised
>if that Lisp system didn't repeat the check three times as part of the
>three instructions involved.  The Lisp system I use here from time to
>time definitely has the check repeated in CAR and CDR -- I just checked.
>(ok, ok, so it's a Scheme, not a Lisp, big deal.)

Microcoded Lisp machines, and other special hardware, tend to make
lots of type checks because it doesn't cost very much.  On
"conventional" machines, most Lisps make such checks in compiled code
only if the code was compiled in some sort of "safe" mode.  Even you
have used at least one Lisp in Edinburgh (Franz Lisp) that makes only
one check in compiled code.  If you want to know what Lisp does (so
that you can makew true statements about it), you have to look at
the practice in a number of different implementations.

>> However, in many Lisps there's only one check because the compiled
>> code for a car or cdr never includes a check.  It's fair to flame Lisp,
>> or at least some Lisp implementations, for being less safe.

>Now that is a serious mistake.  Consider those broken Lisp implementations
>(but not the ones I've used or the one David Warren used) duly flamed.

No one says you have to like the way Lisp works.  That it can be
unsafe is a valid complaint.  In practice, however, the lack of
checks is usually a manageable problem.  If you want to be safer,
you can define some pattern-matching macros that arrange for
cars and cdrs to be taken only when the object is known to be
a cons.

>> But I don't think it's fair to say Lisp makes three checks,
>> because it doesn't.

>It _was_ fair for me to say that, because every Lisp I'd personally checked
>DOES make the three checks.

Well, how many did you check?  If I check one or two Prologs, am I
then justified in making unqualified statements about Prolog as if
my observations were true in general?

>So what I *should* have said is that "a naive Lisp compiler which makes
>the checks which are necessary for safety will do more checking than a
>naive Prolog compiler which makes the checks which are necessary for safety".

Right.

Cheers,
Jeff