[comp.lang.lisp] Self-referencing Closures

eliot@phoenix.Princeton.EDU (Eliot Handelman) (03/07/89)

The situation is this: a process, represented as a closure, spawns a 
child, another closure. The parent then runs the child, and when the
child finishes it returns to the parent. I am doing this using continuations,
that is, the child is passed the parent closure which it then funcalls
when it has finished. So the parent has to be able to pass itself to the
child.

I can let a closure reference itself in the following way:

(defun make-closure ()
  (let (-self-)
    (setq -self- #'(lambda ()
		   <this closure can now reference itself as -self->))))

Does this seem like a particularly bad idea? Is there some important reason
why I would not want to do this? Is there some reason why I wouldn't
want to use SETQ? Can this be done more elegantly? All criticism welcome.

Thanks, Eliot

Krulwich-Bruce@cs.yale.edu (Bruce Krulwich) (03/07/89)

In article <6859@phoenix.Princeton.EDU>, eliot@phoenix (Eliot Handelman)
writes:
>The situation is this: a process, represented as a closure, spawns a 
>child, another closure. The parent then runs the child, and when the
>child finishes it returns to the parent. I am doing this using continuations,
>that is, the child is passed the parent closure which it then funcalls
>when it has finished. So the parent has to be able to pass itself to the
>child.
>
>(defun make-closure ()
>  (let (-self-)
>    (setq -self- #'(lambda ()
>		   <this closure can now reference itself as -self->))))
>
>Does this seem like a particularly bad idea? Is there some important reason
>why I would not want to do this? Is there some reason why I wouldn't
>want to use SETQ? Can this be done more elegantly? All criticism welcome.

There is no need to use the LET/SETQ combination because the LABELS construct
(CLtL p113) exists exactly for this reason.  LABELS allows definition of local
functions that can reference themselves and each other recursively.  The above
code can be written as:

	(defun make-closure ()
	  (labels ((-self- () <code that can reference -self-> ))
	    -self-))


If you really tend towards the boroque you can use "Church's Y operator" which
is defined in Scheme using:

  (define (y f)
   ((lambda (g) (lambda (h) ((f (g g)) h)))
    (lambda (g) (lambda (h) ((f (g g)) h)))))

(the CL version would have alot of FUNCALL and #'s thrown in) to make
recursive closures without using "explicit" recursion constructs.  Using the
above definition you can make a closure to recursively compute the factorial
function by calling:

	(y (lambda (fn)
	      (lambda (x)
		 (if (zerop x) 1 (* x (fn (- x 1)))))))


Anyway, LABELS is what you want.


Bruce Krulwich

 

johnson@csli.STANFORD.EDU (Mark Johnson) (03/08/89)

Bruce Krulwich is quite correct - the LABELS form is what you need
to make these self-referencing closures.  His example contains
a minor bug, however: he forgot to use #' in front of the final -self-
form.  The corrected version is:

(defun make-closure ()
  (labels ((self ()
                 (print 'hello)))
    #'self))

Too much Scheme!  Someone else just sent a message on the net asking
why CommonLisp uses different name spaces for variable and function
definitions.  Personally, I think that this is one of the worst
features of CommonLisp.  It makes my programs look like fields of #'
symbols and funcalls.  It is also one of the hardest things for
students to learn - they get continually confused between the use of
LIST as a function and a variable.  (I know it's bad programming
style, but people do do it).

Mark Johnson

barmar@think.COM (Barry Margolin) (03/08/89)

In article <52880@yale-celray.yale.UUCP> Krulwich-Bruce@cs.yale.edu (Bruce Krulwich) writes:
>	(defun make-closure ()
>	  (labels ((-self- () <code that can reference -self-> ))
>	    -self-))

Actually, the last form should be #'-self-, since LABELS binds the
functional value, not the variable value, of the symbol.

>If you really tend towards the boroque you can use "Church's Y operator" which
>is defined in Scheme using:

You could also simply use LETREC in Scheme.  It binds a variable and
arranges for the scope to include the value form.

Barry Margolin
Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

Krulwich-Bruce@cs.yale.edu (Bruce Krulwich) (03/08/89)

In article <37134@think.UUCP>, barmar@think (Barry Margolin) writes:
>Actually, the last form should be #'-self-, since LABELS binds the
>functional value, not the variable value, of the symbol.
>
>>If you really tend towards the boroque you can use "Church's Y operator" 
>>which is defined in Scheme using:
>
>You could also simply use LETREC in Scheme.  It binds a variable and
>arranges for the scope to include the value form.

Scheme's LETREC is (essentially) the same as CL's LABELS.  I was trying to
show something different by discussion the Y operator.


Bruce