npt-japanese

% Special-Operator FLET, LABELS, MACROLET

UP


Special-Operator FLET, LABELS, MACROLET

Special Operator FLET, LABELS, MACROLET

構文

flet ((function-name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form*
=> result*

labels ((function-name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration form* declaration* form*
=> result*

macrolet ((name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form*
=> result*

引数と戻り値

function-name - 関数名
name - シンボル
lambda-list - ラムダリスト。 fletlabelsは通常のラムダリスト。 macroletはマクロラムダリスト。
local-declaration - 宣言式。評価されません。
declaration - 宣言式。評価されません。
local-documentation - 文字列。評価されません。
local-form, form - 暗黙のprogn
result - formの返却値

定義

fletlabelsmacroletは、 ローカル関数とローカルマクロを定義し、 そのローカルな定義を使いformを実行します。 formは、現れた順に実行します。

fletlabelsによって作成された各関数と、 macroletによって作成された各マクロの それぞれのボディ部のform(ただしラムダリストは除く)は、 必要に応じて、 function-nameの関数のblock名かnameを用いて、 暗黙のblockに囲まれます。

ローカル関数とマクロの定義部のリストと、 fletおよびlabelsのボディ部form間における declarationのスコープは、 ローカルの関数定義の本体が含まれません。 ただし例外はlabelsの、 inlinenotinlineftype宣言であり、 これらはローカルの関数定義を参照し、 そのローカル関数の本体に適用します。 つまり、これらの宣言のスコープは、 関数名として影響を与える範囲と同じです。 これらのdeclarationのスコープには、 macroletで定義されたマクロ展開数の本体は含まれません。

例文

(defun foo (x flag)
  (macrolet ((fudge (z)
                ; パラメーターxとflagはこの時点ではアクセス不可です。
                ; flagの参照はグローバル変数の名前になります。
                ` (if flag (* ,z ,z) ,z)))
   ; パラメーターxとflagは、ここではアクセス可能です。
    (+ x
       (fudge x)
       (fudge (+ x 1)))))
== 
(defun foo (x flag)
  (+ x
     (if flag (* x x) x)
     (if flag (* (+ x 1) (+ x 1)) (+ x 1))))

これは、マクロ展開が行われた後です。 xflagの発生は、 関数fooのパラメータを合法的に参照しています。 なぜなら、これらのパラメータは、 マクロが呼ばれて展開が生成された場所では 見ることができるからです。

(flet ((flet1 (n) (+ n n)))
   (flet ((flet1 (n) (+ 2 (flet1 n))))
     (flet1 2))) =>  6

(defun dummy-function () 'top-level) =>  DUMMY-FUNCTION 
(funcall #'dummy-function) =>  TOP-LEVEL 
(flet ((dummy-function () 'shadow)) 
     (funcall #'dummy-function)) =>  SHADOW 
(eq (funcall #'dummy-function) (funcall 'dummy-function))
=>  true 
(flet ((dummy-function () 'shadow))
  (eq (funcall #'dummy-function)
      (funcall 'dummy-function)))
=>  false 

(defun recursive-times (k n)
  (labels ((temp (n) 
             (if (zerop n) 0 (+ k (temp (1- n))))))
    (temp n))) =>  RECURSIVE-TIMES
(recursive-times 2 3) =>  6

(defmacro mlets (x &environment env) 
   (let ((form `(babbit ,x)))
     (macroexpand form env))) =>  MLETS
(macrolet ((babbit (z) `(+ ,z ,z))) (mlets 5)) =>  10
(flet ((safesqrt (x) (sqrt (abs x))))
 ;; `safesqrt`関数は、二か所で使用されます。
  (safesqrt (apply #'+ (map 'list #'safesqrt '(1 2 3 4 5 6)))))
=>  3.291173
(defun integer-power (n k)     
  (declare (integer n))         
  (declare (type (integer 0 *) k))
  (labels ((expt0 (x k a)
             (declare (integer x a) (type (integer 0 *) k))
             (cond ((zerop k) a)
                   ((evenp k) (expt1 (* x x) (floor k 2) a))
                   (t (expt0 (* x x) (floor k 2) (* x a)))))
           (expt1 (x k a)
             (declare (integer x a) (type (integer 0 *) k))
             (cond ((evenp k) (expt1 (* x x) (floor k 2) a))
                   (t (expt0 (* x x) (floor k 2) (* x a))))))
   (expt0 n k 1))) =>  INTEGER-POWER
(defun example (y l)
  (flet ((attach (x)
           (setq l (append l (list x)))))
    (declare (inline attach))
    (dolist (x y)
      (unless (null (cdr x))
        (attach x)))
    l))

(example '((a apple apricot) (b banana) (c cherry) (d) (e))
         '((1) (2) (3) (4 2) (5) (6 3 2)))
=>  ((1) (2) (3) (4 2) (5) (6 3 2) (A APPLE APRICOT) (B BANANA) (C CHERRY))

影響

なし。

例外

なし。

参考

declare, defmacro, defun, documentation, let, 3.1. 評価, 3.4.11. ドキュメント文字と宣言の文脈的な作用

備考

fletでは、再帰関数を定義することはできません。 labelsは、互いに再帰呼出できる関数を定義するのに使うことができます。

もしmacroletがトップレベルフォームのとき、 ボディ部formもまたトップレベルフォームとして処理されます。 3.2.3. ファイルのコンパイルをご確認ください。


TOP, Github