Предположим, у меня есть замыкание типа "сад-разнообразие", подобное этому простому образцу:
(let ((alpha 0) #| etc. |# )
(lambda ()
(incf alpha)
#| more code here |#
alpha))
Предположим, я (funcall)
экземпляр этого закрытия три раза, и в середине третьего выполнения это закрытие хочет сохранить себя где-нибудь (скажем, в хеш-таблице). Тогда я пока не (funcall)
этот экземпляр. Затем я извлекаю этот экземпляр из хеш-таблицы и (funcall)
снова, получая возвращаемое значение 4.
Как функция в замыкании ссылается на себя, чтобы она могла сохранить себя в этом хэш-таблица?
РЕДАКТИРОВАТЬ 1: Вот более подробный пример. Я достигаю цели, передавая замыкание самому себе в качестве параметра. Но я бы хотел, чтобы замыкание делало все это само по себе, не будучи самопараметрическим.
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
РЕДАКТИРОВАТЬ 2: Да, я знаю, что могу использовать макрос, чтобы вставить имя функции в качестве первого параметра, а затем использовать этот макрос вместо (funcall)
, но я бы все равно хотел бы знать, как позволить замыканию ссылаться на его собственный экземпляр.
РЕДАКТИРОВАТЬ 3: В ответ на любезное предложение SK-logic я сделал следующее, но это не то, что я хочу. Он помещает в стек три новых замыкания, а не три ссылки на одно и то же замыкание. Видите, когда я извлекаю их из стека, значения вызовов равны 1, 1 и 1 вместо 6, 7 и 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
РЕДАКТИРОВАТЬ 4: Предложение Джона О попало точно в цель.Вот код и результат:
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
РЕДАКТИРОВАТЬ 5: Предложение Мирона также попадает в цель и фактически делает код более читаемым:
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