Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Common Lisp
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==Macros== A ''[[Macro (computer science)|macro]]'' in Lisp superficially resembles a function in usage. However, rather than representing an expression which is evaluated, it represents a transformation of the program source code. The macro gets the source it surrounds as arguments, binds them to its parameters and computes a new source form. This new form can also use a macro. The macro expansion is repeated until the new source form does not use a macro. The final computed form is the source code executed at runtime. Typical uses of macros in Lisp: * new control structures (example: looping constructs, branching constructs) * scoping and binding constructs * simplified syntax for complex and repeated source code * top-level defining forms with compile-time side-effects * [[data-driven programming]] * embedded domain specific languages (examples: [[SQL]], [[HTML]], [[Prolog]]) * implicit finalization forms Various standard Common Lisp features also need to be implemented as macros, such as: * the standard <code>setf</code> abstraction, to allow custom compile-time expansions of assignment/access operators * <code>with-accessors</code>, <code>with-slots</code>, <code>with-open-file</code> and other similar <code>WITH</code> macros * Depending on implementation, <code>if</code> or <code>cond</code> is a macro built on the other, the special operator; <code>when</code> and <code>unless</code> consist of macros * The powerful <code>loop</code> domain-specific language Macros are defined by the ''defmacro'' macro. The special operator ''macrolet'' allows the definition of local (lexically scoped) macros. It is also possible to define macros for symbols using ''define-symbol-macro'' and ''symbol-macrolet''. [[Paul Graham (computer programmer)|Paul Graham]]'s book [[On Lisp]] describes the use of macros in Common Lisp in detail. [[Doug Hoyte]]'s book [[Let Over Lambda]] extends the discussion on macros, claiming "Macros are the single greatest advantage that lisp has as a programming language and the single greatest advantage of any programming language." Hoyte provides several examples of iterative development of macros. ===Example using a macro to define a new control structure=== Macros allow Lisp programmers to create new syntactic forms in the language. One typical use is to create new control structures. The example macro provides an <code>until</code> looping construct. The syntax is: <syntaxhighlight lang="text"> (until test form*) </syntaxhighlight> The macro definition for ''until'': <syntaxhighlight lang="lisp"> (defmacro until (test &body body) (let ((start-tag (gensym "START")) (end-tag (gensym "END"))) `(tagbody ,start-tag (when ,test (go ,end-tag)) (progn ,@body) (go ,start-tag) ,end-tag))) </syntaxhighlight> ''tagbody'' is a primitive Common Lisp special operator which provides the ability to name tags and use the ''go'' form to jump to those tags. The backquote ''`'' provides a notation that provides code templates, where the value of forms preceded with a comma are filled in. Forms preceded with comma and at-sign are ''spliced'' in. The tagbody form tests the end condition. If the condition is true, it jumps to the end tag. Otherwise, the provided body code is executed and then it jumps to the start tag. An example of using the above ''until'' macro: <syntaxhighlight lang="lisp"> (until (= (random 10) 0) (write-line "Hello")) </syntaxhighlight> The code can be expanded using the function ''macroexpand-1''. The expansion for the above example looks like this: <syntaxhighlight lang="lisp"> (TAGBODY #:START1136 (WHEN (ZEROP (RANDOM 10)) (GO #:END1137)) (PROGN (WRITE-LINE "hello")) (GO #:START1136) #:END1137) </syntaxhighlight> During macro expansion the value of the variable ''test'' is ''(= (random 10) 0)'' and the value of the variable ''body'' is ''((write-line "Hello"))''. The body is a list of forms. Symbols are usually automatically upcased. The expansion uses the TAGBODY with two labels. The symbols for these labels are computed by GENSYM and are not interned in any package. Two ''go'' forms use these tags to jump to. Since ''tagbody'' is a primitive operator in Common Lisp (and not a macro), it will not be expanded into something else. The expanded form uses the ''when'' macro, which also will be expanded. Fully expanding a source form is called ''code walking''. In the fully expanded (''walked'') form, the ''when'' form is replaced by the primitive ''if'': <syntaxhighlight lang="lisp"> (TAGBODY #:START1136 (IF (ZEROP (RANDOM 10)) (PROGN (GO #:END1137)) NIL) (PROGN (WRITE-LINE "hello")) (GO #:START1136)) #:END1137) </syntaxhighlight> All macros must be expanded before the source code containing them can be evaluated or compiled normally. Macros can be considered functions that accept and return [[S-expression]]s β similar to [[abstract syntax tree]]s, but not limited to those. These functions are invoked before the evaluator or compiler to produce the final source code. Macros are written in normal Common Lisp, and may use any Common Lisp (or third-party) operator available. ===Variable capture and shadowing=== Common Lisp macros are capable of what is commonly called ''variable capture'', where symbols in the macro-expansion body coincide with those in the calling context, allowing the programmer to create macros wherein various symbols have special meaning. The term ''variable capture'' is somewhat misleading, because all namespaces are vulnerable to unwanted capture, including the operator and function namespace, the tagbody label namespace, catch tag, condition handler and restart namespaces. ''Variable capture'' can introduce software defects. This happens in one of the following two ways: * In the first way, a macro expansion can inadvertently make a symbolic reference which the macro writer assumed will resolve in a global namespace, but the code where the macro is expanded happens to provide a local, shadowing definition which steals that reference. Let this be referred to as type 1 capture. * The second way, type 2 capture, is just the opposite: some of the arguments of the macro are pieces of code supplied by the macro caller, and those pieces of code are written such that they make references to surrounding bindings. However, the macro inserts these pieces of code into an expansion which defines its own bindings that accidentally captures some of these references. The Scheme dialect of Lisp provides a macro-writing system which provides the referential transparency that eliminates both types of capture problem. This type of macro system is sometimes called "hygienic", in particular by its proponents (who regard macro systems which do not automatically solve this problem as unhygienic). {{Citation needed|date=May 2011}} In Common Lisp, macro hygiene is ensured one of two different ways. One approach is to use [[gensym]]s: guaranteed-unique symbols which can be used in a macro-expansion without threat of capture. The use of gensyms in a macro definition is a manual chore, but macros can be written which simplify the instantiation and use of gensyms. Gensyms solve type 2 capture easily, but they are not applicable to type 1 capture in the same way, because the macro expansion cannot rename the interfering symbols in the surrounding code which capture its references. Gensyms could be used to provide stable aliases for the global symbols which the macro expansion needs. The macro expansion would use these secret aliases rather than the well-known names, so redefinition of the well-known names would have no ill effect on the macro. Another approach is to use packages. A macro defined in its own package can simply use internal symbols in that package in its expansion. The use of packages deals with type 1 and type 2 capture. However, packages don't solve the type 1 capture of references to standard Common Lisp functions and operators. The reason is that the use of packages to solve capture problems revolves around the use of private symbols (symbols in one package, which are not imported into, or otherwise made visible in other packages). Whereas the Common Lisp library symbols are external, and frequently imported into or made visible in user-defined packages. The following is an example of unwanted capture in the operator namespace, occurring in the expansion of a macro: <syntaxhighlight lang="lisp"> ;; expansion of UNTIL makes liberal use of DO (defmacro until (expression &body body) `(do () (,expression) ,@body)) ;; macrolet establishes lexical operator binding for DO (macrolet ((do (...) ... something else ...)) (until (= (random 10) 0) (write-line "Hello"))) </syntaxhighlight> The <code>until</code> macro will expand into a form which calls <code>do</code> which is intended to refer to the standard Common Lisp macro <code>do</code>. However, in this context, <code>do</code> may have a completely different meaning, so <code>until</code> may not work properly. Common Lisp solves the problem of the shadowing of standard operators and functions by forbidding their redefinition. Because it redefines the standard operator <code>do</code>, the preceding is actually a fragment of non-conforming Common Lisp, which allows implementations to diagnose and reject it.
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)