% 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 - ラムダリスト。
flet
とlabels
は通常のラムダリスト。
macrolet
はマクロラムダリスト。
local-declaration - 宣言式。評価されません。
declaration - 宣言式。評価されません。
local-documentation - 文字列。評価されません。
local-form, form - 暗黙のprogn
result - formの返却値
flet
、labels
、macrolet
は、
ローカル関数とローカルマクロを定義し、
そのローカルな定義を使いformを実行します。
formは、現れた順に実行します。
flet
とlabels
によって作成された各関数と、
macrolet
によって作成された各マクロの
それぞれのボディ部のform(ただしラムダリストは除く)は、
必要に応じて、
function-nameの関数のblock
名かnameを用いて、
暗黙のblock
に囲まれます。
ローカル関数とマクロの定義部のリストと、
flet
およびlabels
のボディ部form間における
declarationのスコープは、
ローカルの関数定義の本体が含まれません。
ただし例外はlabels
の、
inline
、notinline
、ftype
宣言であり、
これらはローカルの関数定義を参照し、
そのローカル関数の本体に適用します。
つまり、これらの宣言のスコープは、
関数名として影響を与える範囲と同じです。
これらのdeclarationのスコープには、
macrolet
で定義されたマクロ展開数の本体は含まれません。
flet
flet
は、ローカルに名前がある関数を定義し、
それらの定義を束縛とともに一連のformを実行します。
そのようなローカル関数はいくつでも定義できます。
flet
のボディ部内では、
flet
によって定義されたfunction-nameという名前は、
同名のグローバルに宣言されたものではなく、
ローカルに宣言された関数が参照されます。
flet
のスコープ内では、
flet
によって定義されている
function-nameという名前の、
グローバルのsetf-expanderの定義は適用されません。
これは、(defmethod (setf f) ...)
ではなく、
(defsetf f ...)
に適用されることに注意してください。
flet
によって定義された関数名は、レキシカルな環境内のものであり、
それらのローカルな定義は、ただflet
本体内でのみ保持されます。
関数定義の束縛は、flet
本体でのみ見ることができ、
それらの定義自身では見ることができません。
関数定義内において、
ローカルの関数名で定義されているものを探すときは、
flet
の外側で定義された関数かマクロが参照されます。
flet
は、局所的にグローバル関数名を隠蔽することができ、
その新しい定義は、グローバルな定義を参照することができます。
labels
macrolet
macrolet
は、defmacro
と同じフォーマットで、
ローカルマクロの定義を確立します。
macrolet
の内部では、
macrolet
によって定義されている
function-nameという名前の、
グローバルのsetf-expanderの定義は適用されません。
そうではなく、setf
はマクロフォームを展開し、
結果のフォームを再帰的に処理します。
macrolet
によって定義されたマクロ展開関数は、
macrolet
のフォームに現れる、
レキシカルな環境によって定義されたものです。
宣言と、macrolet
とsymbol-macrolet
の定義は、
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))))
これは、マクロ展開が行われた後です。
x
とflag
の発生は、
関数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. ファイルのコンパイルをご確認ください。