User Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cl:special_operators:flet [2019/09/14 05:00]
cl:special_operators:flet [2019/09/19 02:00] (current)
Line 1: Line 1:
 +====== Special Operator FLET, LABELS, MACROLET ======
 +
 +====Syntax====
 +  * **flet** ((//​function-name lambda-list <​nowiki>​[[</​nowiki>​local-declaration''​*''​ | local-documentation<​nowiki>​]]</​nowiki>​ local-form''​*''​)''​*''​) declaration''​*''​ form''​*''//​ → //​result''​*''//​
 +  * **labels** ((//​function-name lambda-list <​nowiki>​[[</​nowiki>​local-declaration''​*''​ | local-documentation<​nowiki>​]]</​nowiki>​ local-form''​*''​)''​*''​) declaration''​*''​ form''​*''//​ → //​result''​*''//​
 +  * **macrolet** ((//name lambda-list <​nowiki>​[[</​nowiki>​local-declaration''​*''​ | local-documentation<​nowiki>​]]</​nowiki>​ local-form''​*''​)''​*''​) declaration''​*''​ form''​*''//​ → //​result''​*''//​
 +
 +====Arguments and Values====
 +  * //​function-name//​ - a //​[[CL:​Glossary:​function name]]//.
 +  * //name// - a //​[[CL:​Glossary:​symbol]]//​.
 +  * //​lambda-list//​ - a //​[[CL:​Glossary:​lambda list]]//; for **flet** and **labels**, it is an //​[[CL:​Glossary:​ordinary lambda list]]//; for **macrolet**,​ it is a //​[[CL:​Glossary:​macro lambda list]]//.
 +  * //​local-declaration//​ - a **[[CL:​Special Operators:​declare]]** //​[[CL:​Glossary:​expression]]//;​ not evaluated.
 +  * //​declaration//​ - a **[[CL:​Special Operators:​declare]]** //​[[CL:​Glossary:​expression]]//;​ not evaluated.
 +  * //​local-documentation//​ - a //​[[CL:​Glossary:​string]]//;​ not evaluated.
 +  * //​local-forms//,​ //forms// - an //​[[CL:​Glossary:​implicit progn]]//.
 +  * //results// - the //​[[CL:​Glossary:​value|values]]//​ of the //forms//.
 +
 +====Description====
 +**flet**, **labels**, and **macrolet** define local //​[[CL:​Glossary:​function|functions]]//​ and //​[[CL:​Glossary:​macro|macros]]//,​ and execute //forms// using the local definitions. //Forms// are executed in order of occurrence.
 +
 +The body forms (but not the //​[[CL:​Glossary:​lambda list]]//) of each //​[[CL:​Glossary:​function]]//​ created by **flet** and **labels** and each //​[[CL:​Glossary:​macro]]//​ created by **macrolet** are enclosed in an //​[[CL:​Glossary:​implicit block]]// whose name is the //​[[CL:​Glossary:​function block name]]// of the //​function-name//​ or //name//, as appropriate.
 +
 +The scope of the //​declarations//​ between the list of local function/​macro definitions and the body //forms// in **flet** and **labels** does not include the bodies of the locally defined //​[[CL:​Glossary:​function|functions]]//,​ except that for **labels**, any **[[CL:​Declarations:​inline]]**,​ **[[CL:​Declarations:​notinline]]**,​ or **[[CL:​Declarations:​ftype]]** declarations that refer to the locally defined functions do apply to the local function bodies. That is, their //​[[CL:​Glossary:​scope]]//​ is the same as the function name that they affect.
 +
 +The scope of these //​declarations//​ does not include the bodies of the macro expander functions defined by **macrolet**.
 +
 +===flet===
 +**flet** defines locally named //​[[CL:​Glossary:​function|functions]]//​ and executes a series of //forms// with these definition //​[[CL:​Glossary:​binding|bindings]]//​. Any number of such local //​[[CL:​Glossary:​function|functions]]//​ can be defined.
 +
 +The //​[[CL:​Glossary:​scope]]//​ of the name //​[[CL:​Glossary:​binding]]//​ encompasses only the body. Within the body of **flet**, //​function-names//​ matching those defined by **flet** refer to the locally defined //​[[CL:​Glossary:​function|functions]]//​ rather than to the global function definitions of the same name.
 +
 +Also, within the scope of **flet**, global //​[[CL:​Glossary:​setf expander]]//​ definitions of the //​function-name//​ defined by **flet** do not apply.
 +
 +Note that this applies to ''​([[CL:​Macros:​defsetf]] f ...)'',​ not ''​([[Cl:​Macros:​defmethod]] ([[CL:​Macros:​setf]] ''​f''​) ...)''​.
 +
 +The names of //​[[CL:​Glossary:​function|functions]]//​ defined by **flet** are in the //​[[CL:​Glossary:​lexical environment]]//;​ they retain their local definitions only within the body of **flet**. The function definition bindings are visible only in the body of **flet**, not the definitions themselves. Within the function definitions,​ local function names that match those being defined refer to //​[[CL:​Glossary:​function|functions]]//​ or //​[[CL:​Glossary:​macro|macros]]//​ defined outside the **flet**. **flet** can locally //​[[CL:​Glossary:​shadow]]//​ a global function name, and the new definition can refer to the global definition.
 +
 +Any //​local-documentation//​ is attached to the corresponding local //​function//​ (if one is actually created) as a //​[[CL:​Glossary:​documentation string]]//.
 +
 +===labels===
 +**labels** is equivalent to **flet** except that the scope of the defined function names for **labels** encompasses the function definitions themselves as well as the body.
 +
 +===macrolet===
 +**macrolet** establishes local //​[[CL:​Glossary:​macro]]//​ definitions,​ using the same format used by **[[CL:​Macros:​defmacro]]**.
 +
 +Within the body of **macrolet**,​ global //​[[CL:​Glossary:​setf expander]]//​ definitions of the //names// defined by the **macrolet** do not apply; rather, **[[CL:​Macros:​setf]]** expands the //​[[CL:​Glossary:​macro form]]// and recursively process the resulting //​[[CL:​Glossary:​form]]//​.
 +
 +The macro-expansion functions defined by **macrolet** are defined in the //​[[CL:​Glossary:​lexical environment]]//​ in which the **macrolet** form appears.
 +
 +Declarations and **macrolet** and **[[CL:​Special Operators:​symbol-macrolet]]** definitions affect the local macro definitions in a **macrolet**,​ but the consequences are undefined if the local macro definitions reference any local //​[[CL:​Glossary:​variable]]//​ or //​[[CL:​Glossary:​function]]//​ //​[[CL:​Glossary:​binding|bindings]]//​ that are visible in that //​[[CL:​Glossary:​lexical environment]]//​.
 +
 +Any //​local-documentation//​ is attached to the corresponding local //macro function// as a //​[[CL:​Glossary:​documentation string]]//.
 +
 +====Examples====
 +<​blockquote>​
 +([[CL:​Macros:​defun]] foo (x flag)
 +  (macrolet ((fudge (z) 
 +               ; The parameters x and flag are not accessible ​
 +               ; at this point; a reference to flag would be to 
 +               ; the global variable of that name.
 +               ​([[CL:​Special Operators:​if]] flag ([[CL:​Functions:​math-multiply|*]] ,z ,z) ,z)))
 +    ; The parameters x and flag are accessible here.
 +    ([[CL:​Functions:​math-add|+]] x (fudge x) (fudge ([[CL:​Functions:​math-add|+]] x 1)))))
 +</​blockquote>​
 +
 +After macroexpansion,​ this is equivalent to:
 +
 +<​blockquote>​
 +([[CL:​Macros:​defun]] foo (x flag) 
 +  ([[CL:​Functions:​math-add|+]] x ([[CL:​Special Operators:​if]] flag ([[CL:​Functions:​math-multiply|*]] x x) x) ([[CL:​Special Operators:​if]] flag ([[CL:​Functions:​math-multiply|*]] ([[CL:​Functions:​math-add|+]] x 1) ([[CL:​Functions:​math-add|+]] x 1)) ([[CL:​Functions:​math-add|+]] x 1))))
 +</​blockquote>​
 +
 +The occurrences of ''​x''​ and ''​flag''​ legitimately refer to the parameters of the function ''​foo''​ because those parameters are visible at the site of the macro call which produced the expansion.
 +
 +<​blockquote>​
 +(flet ((flet1 (n) ([[CL:​Functions:​math-add|+]] n n)))
 +  (flet ((flet1 (n) ([[CL:​Functions:​math-add|+]] 2 (flet1 n))))
 +    (flet1 2))) <​r>​6</​r>​
 +
 +([[CL:​Macros:​defun]] dummy-function () '​top-level) <​r>​DUMMY-FUNCTION</​r>​
 +([[CL:​Functions:​funcall]] #'​dummy-function) <​r>​TOP-LEVEL</​r>​
 +(flet ((dummy-function () '​shadow))
 +  ([[CL:​Functions:​funcall]] #'​dummy-function)) → SHADOW ​
 +([[CL:​Functions:​eq]] ([[CL:​Functions:​funcall]] #'​dummy-function) ([[CL:​Functions:​funcall]] '​dummy-function)) <​r>//​[[CL:​Glossary:​true]]//​ </r>
 +(flet ((dummy-function () '​shadow))
 +  ([[CL:​Functions:​eq]] ([[CL:​Functions:​funcall]] #'​dummy-function) ([[CL:​Functions:​funcall]] '​dummy-function))) <​r>//​[[CL:​Glossary:​false]]//</​r>​
 +
 +([[CL:​Macros:​defun]] recursive-times (k n) 
 +  (labels ((temp (n) ([[CL:​Special Operators:​if]] ([[CL:​Functions:​zerop]] n) 0 ([[CL:​Functions:​math-add|+]] k (temp ([[CL:​Functions:​math-one-minus|1-]] n))))))
 +    (temp n))) <​r>​RECURSIVE-TIMES </r>
 +(recursive-times 2 3) <​r>​6</​r>​
 +
 +([[CL:​Macros:​defmacro]] mlets (x &​environment env)
 +  ([[CL:​Special Operators:​let]] ((form `(babbit ,x)))
 +    ([[CL:​Functions:​macroexpand]] form env))) <​r>​MLETS</​r>​
 +(macrolet ((babbit (z) `(+ ,z ,z)))
 +  (mlets 5)) <​r>​10</​r>​
 +
 +(flet ((safesqrt (x) ([[CL:​Functions:​sqrt]] ([[CL:​Functions:​abs]] x))))
 +  (safesqrt ([[CL:​Functions:​apply]] #'​[[CL:​Functions:​math-add|+]] ([[CL:​Functions:​map]] '​[[CL:​Types:​list]] #'​safesqrt '(1 2 3 4 5 6))))) <​r>​3.291173</​r>​
 +</​blockquote>​
 +
 +In the example above, the ''​safesqrt''​ function is used in two places. ​
 +
 +<​blockquote>​
 +([[CL:​Macros:​defun]] integer-power (n k)
 +  ([[CL:​Symbols:​declare]] ([[CL:​Types:​integer]] n))
 +  ([[CL:​Symbols:​declare]] ([[CL:​Declarations:​type]] ([[CL:​Types:​integer]] 0 [[CL:​Types:​wildcard|*]]) k))
 +  (labels ((expt0 (x k a)
 +             ​([[CL:​Symbols:​declare]] ([[CL:​Types:​integer]] x a) ([[CL:​Declarations:​type]] ([[CL:​Types:​integer]] 0 [[CL:​Types:​wildcard|*]]) k))
 +             ​([[CL:​Macros:​cond]] (([[CL:​Functions:​zerop]] k) a)
 +                   ​(([[CL:​Functions:​evenp]] k) (expt1 ([[CL:​Functions:​math-multiply|*]] x x) ([[CL:​Functions:​floor]] k 2) a))
 +                   ​([[CL:​Constant Variables:​t]] (expt0 (* x x) ([[CL:​Functions:​floor]] k 2) (* x a)))))
 +           ​(expt1 (x k a)
 +             ​([[CL:​Symbols:​declare]] ([[CL:​Types:​integer]] x a) ([[CL:​Declarations:​type]] ([[CL:​Types:​integer]] 0 [[CL:​Types:​wildcard|*]]) k))
 +             ​([[CL:​Macros:​cond]] (([[CL:​Functions:​evenp]] k) (expt1 ([[CL:​Functions:​math-multiply|*]] x x) ([[CL:​Functions:​floor]] k 2) a))
 +                    ([[CL:​Constant Variables:​t]] (expt0 ([[CL:​Functions:​math-multiply|*]] x x) ([[CL:​Functions:​floor]] k 2) ([[CL:​Functions:​math-multiply|*]] x a))))))
 +  (expt0 n k 1))) <​r>​INTEGER-POWER</​r>​
 +
 +([[CL:​Macros:​defun]] example (y l)
 +  (flet ((attach (x) ([[CL:​Macros:​setf]] l ([[CL:​Functions:​append]] l ([[CL:​Functions:​list]] x)))))
 +    ([[CL:​Symbols:​declare]] ([[CL:​Declarations:​inline]] attach))
 +    ([[CL:​Macros:​dolist]] (x y) ([[CL:​Macros:​unless]] ([[CL:​Functions:​null]] ([[CL:​Functions:​cdr]] x)) (attach x)))
 +    l)) <​r>​EXAMPLE</​r>​
 +
 +(example '((a apple apricot) (b banana) (c cherry) (d) (e)) 
 +         '​((1) (2) (3) (4 2) (5) (6 3 2)))
 +<​r>​((1) (2) (3) (4 2) (5) (6 3 2) (A APPLE APRICOT) (B BANANA) (C CHERRY))</​r>​
 +</​blockquote>​
 +
 +====Affected By====
 +None.
 +
 +====Exceptional Situations====
 +None.
 +
 +====See Also====
 +  * **[[CL:​Special Operators:​declare|Special Operator DECLARE]]**
 +  * **[[CL:​Macros:​defmacro|Macro DEFMACRO]]**
 +  * **[[CL:​Macros:​defun|Macro DEFUN]]**
 +  * **[[CL:​Functions:​documentation|Generic Function DOCUMENTATION]]**
 +  * **[[CL:​Special Operators:​let|Special Operator LET]]**
 +  * {\secref\Evaluation}
 +  * {\secref\DocVsDecls}
 +
 +====Notes====
 +It is not possible to define recursive //​[[CL:​Glossary:​function|functions]]//​ with **flet**. **labels** can be used to define mutually recursive //​[[CL:​Glossary:​function|functions]]//​.
 +
 +If a **macrolet** //​[[CL:​Glossary:​form]]//​ is a //​[[CL:​Glossary:​top level form]]//, the body //forms// are also processed as //​[[CL:​Glossary:​top level forms]]//. see section {\secref\FileCompilation}.
 +
 +\issue{DECLARATION-SCOPE:​NO-HOISTING} \issue{SETF-METHOD-VS-SETF-METHOD:​RENAME-OLD-TERMS} \issue{GET-SETF-METHOD-ENVIRONMENT:​ADD-ARG} \issue{SETF-METHOD-VS-SETF-METHOD:​RENAME-OLD-TERMS} \issue{GET-SETF-METHOD-ENVIRONMENT:​ADD-ARG} \issue{SETF-METHOD-VS-SETF-METHOD:​RENAME-OLD-TERMS} \issue{GET-SETF-METHOD-ENVIRONMENT:​ADD-ARG} \issue{DEFINING-MACROS-NON-TOP-LEVEL:​ALLOW} \issue{LISP-SYMBOL-REDEFINITION:​MAR89-X3J13} \issue{FLET-DECLARATIONS} \issue{DECLS-AND-DOC} \issue{FLET-DECLARATIONS:​ALLOW} \issue{FUNCTION-NAME:​LARGE} \issue{FLET-IMPLICIT-BLOCK:​YES} \issue{FUNCTION-NAME:​LARGE} \issue{DEFMACRO-BLOCK-SCOPE:​EXCLUDES-BINDINGS} \issue{FLET-DECLARATIONS}