How to jump out of a function in Lisp?

Is it possible in (Common) Lisp to switch to another function instead of calling another? I mean, the current function is broken, and the other is called without jumping over thousands of functions, as if I myself decided whether there would be optimization of the tail call, even if it is not the tail. I'm not sure that "(return-from fn x)" does what I want.

Example:

(defun fn (x)
  (when x
    (princ x)
    (jump 'fn (cdr x)))
  (rest))

"jump" should resemble the following function, without preserving the position of this function, instead returning to where the original funcall function was, so there will be no stack overflow. "rest" should only be executed if x is zero.

+3
source share
3 answers

?

(defun fn (x)
  (if x
      (progn
        (princ x)
        (fn (cdr x)))
      (progn
        (rest))))

fn . , . , . " ", "X" Common Lisp.

+4

, , , () , , ( , ). , , . Common Lisp:

(defstruct thunk closure)

(defmacro thunk (&body body)
  `(make-thunk :closure (lambda () ,@body)))

(defun trampoline (thunk)
  (do ((thunk thunk (funcall (thunk-closure thunk))))
      ((not (thunk-p thunk)) thunk)))

, thunk, . , . thunk, , , , thunk. , mapcar:

(defun t-mapcar1 (function list)
  (labels ((m (list acc)
             (if (endp list)
                 (nreverse acc)
                 (thunk 
                   (m (rest list)
                      (list* (funcall function (first list)) acc))))))
    (m list '())))

, :

CL-USER> (t-mapcar1 '1+ '())
NIL

, thunk:

CL-USER> (t-mapcar1 '1+ '(1 2))
#S(THUNK :CLOSURE #<CLOSURE (LAMBDA #) {10033C7B39}>)

, ( , ):

CL-USER> (trampoline (t-mapcar1 '1+ '()))
NIL
CL-USER> (trampoline (t-mapcar1 '1+ '(1 2)))
(2 3)
CL-USER> (trampoline (t-mapcar1 '1+ '(1 2 3 4)))
(2 3 4 5)

, ,

(defun fn (x)
  (when x
    (princ x)
    (jump 'fn (cdr x)))
  (rest))

. return fn, thunk "" , .

(defun fn (x)
  (when x
    (princ x)
    (return (thunk (fn (cdr x)))))
  (rest))
+5

, . -

(defmacro recurr (name bindings &body body)
  (let* ((names (mapcar #'car bindings))
         (restart (gensym "RESTART-"))
         (temp1 (gensym))
         (temp2 (gensym))
         (shadows (mapcar (lambda (name) (declare (ignore name)) (gensym)) names)))
    `(block ,name
       (let ,bindings
         (macrolet ((,name ,shadows
                      (list 'progn
                            (cons 'psetq
                                  (loop
                                    :for ,temp1 :in ',names
                                    :for ,temp2 :in (list ,@shadows)
                                    :nconcing (list ,temp1 ,temp2)))
                            (list 'go ',restart))))
           (tagbody
              ,restart
              (progn ,@body)))))))                

-let, :

(recurr traverse ((list '(1 2 3 4)))
   (if (null list) 'end 
       (traverse (cdr list))))

  • , (traverse ), , .. funcall apply it
  • (.. , )

(defmacro label (name (&rest bindings) &body body)
  `(labels ((,name ,(mapcar #'first bindings) ,@body))
     (,name ,@(mapcar #'second bindings))))

, "look ma, no stack space consing".

0

All Articles