Suppose I have a garden-variety closure like this bare-bones sample:
(let ((alpha 0) #| etc. |# )
(lambda ()
(incf alpha)
#| more code here |#
alpha))
Suppose I (funcall)
an instance of that closure three times, and in the middle of the third execution, this closure wants to save itself somewhere (in a hash table, say). Then I don't (funcall)
this instance for a while. Then I retrieve this instance from the hash table and (funcall)
it again, getting the returned value of 4.
How does the function in the closure refer to itself, so it can save itself in that hash table?
EDIT 1: Here's a more detailed example. I accomplish the goal by passing the closure to itself as a parameter. But I'd like the closure to do all this to itself without being self-parameterized.
1 (defparameter *listeriosis* nil)
2 (defparameter *a*
3 (lambda ()
4 (let ((count 0))
5 (lambda (param1 param2 param3 self)
6 (incf count)
7 (when (= 3 count)
8 (push self *listeriosis*)
9 (push self *listeriosis*)
10 (push self *listeriosis*))
11 count))))
12 (let ((bee (funcall *a*)))
13 (princ (funcall bee 1 2 3 bee)) (terpri)
14 (princ (funcall bee 1 2 3 bee)) (terpri)
15 (princ (funcall bee 1 2 3 bee)) (terpri)
16 (princ (funcall bee 1 2 3 bee)) (terpri)
17 (princ (funcall bee 1 2 3 bee)) (terpri))
18 (princ "///") (terpri)
19 (princ (funcall (pop *listeriosis*) 1 2 3 nil)) (terpri)
20 (princ (funcall (pop *listeriosis*) 1 2 3 nil)) (terpri)
21 (princ (funcall (pop *listeriosis*) 1 2 3 nil)) (terpri)
1
2
3
4
5
///
6
7
8
EDIT 2: Yes, I know I can use a macro to slip the name of the function in as its first parameter, and then use that macro instead of (funcall)
, but I'd still like to know how to let a closure refer to its own instance.
EDIT 3: In response to SK-logic's kind suggestion, I did the following, but it doesn't do what I want. It pushes three new closures on the stack, not three references to the same closure. See how when I pop those off the stack, the values of the calls are 1, 1, and 1 instead of 6, 7, and 8?
1 (defparameter *listeriosis* nil)
2 (defun Y (f)
3 ((lambda (x) (funcall x x))
4 (lambda (y)
5 (funcall f (lambda (&rest args)
6 (apply (funcall y y) args))))))
7 (defparameter *a*
8 (lambda (self)
9 (let ((count 0))
10 (lambda (param1 param2 param3)
11 (incf count)
12 (when (= 3 count)
13 (push self *listeriosis*)
14 (push self *listeriosis*)
15 (push self *listeriosis*))
16 count))))
17 (let ((bee (Y *a*)))
18 (princ (funcall bee 1 2 3 #| bee |# )) (terpri)
19 (princ (funcall bee 1 2 3 #| bee |# )) (terpri)
20 (princ (funcall bee 1 2 3 #| bee |# )) (terpri)
21 (princ (funcall bee 1 2 3 #| bee |# )) (terpri)
22 (princ (funcall bee 1 2 3 #| bee |# )) (terpri))
23 (princ "///") (terpri)
24 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri)
25 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri)
26 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri)
1
2
3
4
5
///
1
1
1
EDIT 4: Jon O's suggestion hit the mark exactly. Here's the code and output:
1 (defparameter *listeriosis* nil)
2 (defparameter *a*
3 (lambda ()
4 (let ((count 0))
5 (labels ((self (param1 param2 param3)
6 (incf count)
7 (when (= 3 count)
8 (push (function self) *listeriosis*)
9 (push (function self) *listeriosis*)
10 (push (function self) *listeriosis*))
11 count))
12 (function self)))))
13 (let ((bee (funcall *a*)))
14 (princ (funcall bee 1 2 3)) (terpri)
15 (princ (funcall bee 1 2 3)) (terpri)
16 (princ (funcall bee 1 2 3)) (terpri)
17 (princ (funcall bee 1 2 3)) (terpri)
18 (princ (funcall bee 1 2 3)) (terpri))
19 (princ "///") (terpri)
20 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri)
21 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri)
22 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri)
1
2
3
4
5
///
6
7
8
EDIT 5: Miron's suggestion also hits the mark, and actually makes the code a bit more readable:
1 (defmacro alambda (parms &body body)
2 `(labels ((self ,parms ,@body))
3 #'self))
4 ;
5 (defparameter *listeriosis* nil)
6 (defparameter *a*
7 (lambda ()
8 (let ((count 0))
9 (alambda (param1 param2 param3)
10 (incf count)
11 (when (= 3 count)
12 (push #'self *listeriosis*)
13 (push #'self *listeriosis*)
14 (push #'self *listeriosis*))
15 count))))
16 ;
17 (let ((bee (funcall *a*)))
18 (princ (funcall bee 1 2 3)) (terpri)
19 (princ (funcall bee 1 2 3)) (terpri)
20 (princ (funcall bee 1 2 3)) (terpri)
21 (princ (funcall bee 1 2 3)) (terpri)
22 (princ (funcall bee 1 2 3)) (terpri))
23 (princ "///") (terpri)
24 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri)
25 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri)
26 (princ (funcall (pop *listeriosis*) 1 2 3)) (terpri)
1
2
3
4
5
///
6
7
8
What about alambda (also in On Lisp)?
;; Graham's alambda
(defmacro alambda (parms &body body)
`(labels ((self ,parms ,@body))
#'self))