flet と labels の違い

どこかでどっちかは再帰ができないとか聞いた気がしたので確かめてみた。

(defun hoge (&optional arg) 'defun)
=> hoge

(flet ((hoge (&optional arg)
         (if arg (hoge) 'flet)))
  (values (hoge t)
          (hoge nil)))
=> defun
=> flet

(labels ((hoge (&optional arg)
           (if arg (hoge) 'labels)))
  (values (hoge t)
          (hoge nil)))
=> labels
=> labels

flet のローカル関数定義部分では、外のスコープの関数定義を参照する。labels のそれでは、labels で定義しているローカル関数を参照する。てことは labels では再帰できるが flet ではできない。

(flet ((my-length-flet (lst &optional (n 0))
         (if (atom lst)
             n
           (my-length-flet (cdr lst) (1+ n)))))
  (my-length-flet '(a b c d e)))
=> 関数が定義されていません: my-length-flet

(labels ((my-length-labels (lst &optional (n 0))
           (if (atom lst)
               n
             (my-length-labels (cdr lst) (1+ n)))))
  (my-length-labels '(a b c d e)))
=> 5

うん、オーケイ。