[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Issue: TAIL-RECURSION-OPTIMIZATION (Version 2)



> > That's not true, because a function can't reference -itself-, it can
> > only reference -its name-.  For example,
> > 
> > (defun foo (x)
> >   (if (zerop x) 1 (* x (foo (1- x)))))
> > (setf (symbol-function 'bar) (symbol-function 'foo))
> > (defun foo (x)
> >   (* x 2))
> > (bar 3) => 12, not 6
> 
> Good point; this example helps clarify the issue:  is this the behavior
> desired?  I think not, since when the programmer wrote the DEFUN for FOO
> he most likely intended that the call to FOO referred to the function
> he was defining, not to some other FOO that might be defined later.
> Thus, in this case, early binding would cause less surprise than late
> binding.

I agree this is a well-chosen example.

The purist in me says that a user wanting self-recursion should have
written: 

(defun foo (x)
 (labels ((inner-foo (x)
	    (if (zerop x) 1 (* x (inner-foo (1- x))))))
   (inner-foo x)))

But the pragmatist says that this is cumbersome enough that people 
will prefer the simpler version to be self-recursive:

 (defun foo (x)
   (if (zerop x) 1 (* x (foo (1- x)))))

A solution to this quandry that keeps source code simple would be
to use two different function-defining macros for the two kinds of
behavior.  

I.e., DEFUN1 would be a version of DEFUN that produced code using
labels to ensure self-recursion, and DEFUN2 would produce code
that chases through symbols.  Then for backwards compatibility, 
people can argue whether DEFUN should be equated with DEFUN1 or
DEFUN2, or left for the user or vendor to define.

But if the essence of this argument is accepted, then why not let
(DECLARE (NOTINLINE FOO)) or (DECLARE (INLINE FOO)) discriminate the
two forms?  And accepting that premise, it seems that 99.9% of the
time, self-recursion is expected or at worst :-) simply makes the
code run faster.  I think this leads to the solution Lucid adopted
(but probably not through this chain of reasoning.)   

One advantage I see to declarations over DEFUN1/DEFUN2 is that
DEFUN1 doesn't extend easily to collections of inter-callable
functions, but declarations do (via PROCLAIM).

  jlm