продолжение в общем lisp макросами - относительно реализации в OnLisp

ВНа Лиспе, п. 267, Пол Грэм обеспечивает реализацию макроса передачи продолжения:

(setq *cont* #'identity)

(defmacro =lambda (parms &body body)
  `#'(lambda (*cont* ,@parms) ,@body))

(defmacro =defun (name parms &body body)
  (let ((f (intern (concatenate 'string
                "=" (symbol-name name)))))
    `(progn
       (defmacro ,name ,parms
     `(,',f *cont* ,,@parms))
       (defun ,f (*cont* ,@parms) ,@body))))

(defmacro =bind (parms expr &body body)
  `(let ((*cont* #'(lambda ,parms ,@body))) ,expr))

(defmacro =values (&rest retvals)
  `(funcall *cont* ,@retvals))

Следующий код для обхода дереваt2 за каждый лист дереваt1, использует эту реализацию, и мне интересно, что происходит, когдаrestart называется, особенно после того, как листt1 изменилось сA (первый элемент)B (второй элемент). когдаrestart вызывается просто лямбда-функция из*saved*и что лямбда-функции вызываетdft-node с(cdr tree) снова. Но этот звонок сделанвне сфера внешнего=bind, а также=bind был ответственным за связывание*cont*, Как происходит связывание*cont* введенный внешним=bind все еще в области, тогда?

(setq *saved* nil)

(=defun dft-node (tree)
    (cond ((null tree) (restart))
          ((atom tree) (=values tree))
          (t (push #'(lambda () (dft-node (cdr tree))) *saved*)
             (dft-node (car tree)))))

(=defun restart ()
    (if *saved*
        (funcall (pop *saved*))
      (=values 'done)))

(setq t1 '(a (b (d h)) (c e (f i) g))
      t2 '(1 (2 (3 6 7) 4 5)))

(=bind (node1) (dft-node t1)
  (if (eq node1 'done)
      'done
    (=bind (node2) (dft-node t2)
      (list node1 node2))))

Последняя форма расширяется до

(let ((*cont* (lambda (node1)
                (if (eq node1 'done)
                    'done
                    (let ((*cont* (lambda (node2)
                                    (list node1 node2))))
                      (dft-node t2))
  (dft-node t1))))))

Это производит(a 1), По словам Грэма, последующие звонкиrestart должен производить(a 2)и так далее, до(a 5), а затем последующие звонки должны произвести(b 1), (b 2)и так далее, пока, наконец,(g 5):

> (let ((node1 (dft-node t1)))
    (if (eq? node1 ’done)
        ’done
        (list node1 (dft-node t2))))
(A 1)
> (restart)
(A 2)
…
> (restart)
(B 1)

После(a 1)Привязка*cont* установленоlet больше не должно быть на месте. Как сделать последующие звонкиrestart эти значения? Это сфераlet все еще применяется к отдельному вызовуrestart? Что здесь происходит?

Ответы на вопрос(1)

Ваш ответ на вопрос