#:g1: goやreturn-fromを関数の外から与える

Posted 2021-10-28 17:40:05 GMT

コード整理で関数の分割や統合を行なっている際に、return-from等で脱出する場所を上手く小分けにできなかったり、まとめられなかったりする局面がたまにありますが、blockのタグやtagbodyのラベルをクロージャーにして渡してしまえば簡単だということに気付きました。

例えば、このような一つの関数を

(defun foo (int)
  (when (oddp int) (return-from foo (values int 'odd)))
  (print (+ 1 int))
  (print "fin"))

(foo 99) → 99 odd

(foo 98) ▻ ▻ 99 ▻ "fin" → "fin"

二つの関数に分解できます。

(defun bar (int xit)
  (when (oddp int) (funcall xit int))
  (print (+ 1 int)))

(defun foo (int) (bar int (lambda (int) (return-from foo (values int 'odd)))) (print "fin"))

(foo 99) → 99 odd

(foo 98) ▻ ▻ 99 ▻ "fin" → "fin"

tagbodyのラベルも同様です。

(defun foo (int &aux ans)
  (tagbody 
    (bar int (lambda (int) 
               (setq ans int)
               (go X)))
    (print "fin")
  X (return-from foo ans)))

まとめ

リファクタリング作業等ではたまに使えることもあるかもしれません。
ちなみに、tagbodyのラベルもblockのブロック名もレキシカル変数とは違って有限エクステントなので、式の外へは持ち出せませんので注意しましょう。


HTML generated by 3bmd in LispWorks 7.0.0

comments powered by Disqus