3

(Common) Lispで別の関数を呼び出す代わりに別の関数にジャンプすることは可能ですか? つまり、現在の関数が壊れて別の関数が呼び出され、何千もの関数をジャンプバックせずに、末尾でなくても末尾呼び出しの最適化が行われているかどうかを自分で決めるかのように。"(return-from fn x)" が必要かどうかはわかりません。

例:

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

「ジャンプ」は、スタック オーバーフローが発生しないように、この関数の位置を保存せずに、元の funcall があった場所に戻る代わりに、次の関数を呼び出すようなものでなければなりません。'rest' は、x が nil の場合にのみ実行する必要があります。

4

3 に答える 3

0

まあ、そうではありません。私はかつて実験をしました

(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)))))))                

そして、スキームの名前付きレットのように使用されます。例:

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

しかし:

  1. 定義されたオブジェクト (例) は関数でtraverseはありませんfuncallapply
  2. この種の構造は、再帰構造に実際には対応していません (つまり、スタックが保持されないため、シーケンスの代わりに任意のツリーをトラバースするために使用することはできません)。

別のアプローチは

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

これは実際に言及されたポイントに対処しますが、「ルックマ、​​スタックスペースのコンシングなし」プロパティを失います。

于 2014-02-26T13:21:08.770 に答える