Reputation: 742
Just do not understand the description of macro used for operators which creates context. It seems to me that if there is a binding, macro is the only choice.
Is this cannot be achieved by other means? What does the text below really mean?
Thanks a lot.
There is another kind of context besides a lexical environment. In the broader sense, the context is the state of theworld, including the values of special variables, the contents of data structures, and the state of things outside Lisp. Operators which build this kind of context must be defined as macros too, unless their code bodies are to be packaged up in closures. The names of context-building macros often begin with with-. The most commonly used macro of this type is probably with-open-file. Its body is evaluated with a newly opened file bound to a user-supplied variable:
(with-open-file (s "dump" :direction :output)
(princ 99 s))
......
This operator clearly has to be defined as amacro,because it binds s. However, operators which cause forms to be evaluated in a new context must be defined as macros anyway.
Upvotes: 4
Views: 131
Reputation: 139401
A form which needs to be executed in a new environment can be defined in two ways:
What's not possible is this:
(this-is-some-function-with-some-file-opened (princ 99))
Above is not possible, because the princ
form will be executed before the function this-is-some-function-with-some-file-opened
. Argument forms are executed before the called function. The values of these argument forms will then be passed to the called function.
Thus for the functional version, the body form needs to be passed as a function, which later will be called with the necessary arguments. The macro variant will already expand into the necessary forms and place the body form inside this.
The typical macro version:
(with-open-file (s "dump" :direction :output)
(princ 99 s))
A version using a function:
(call-with-open-file
(lambda (s)
(princ 99 s))
"dump"
:direction :output)
In above one passes in the body as a function and then various parameter follow. From a functional view this is fine. But Common Lisp does not have this function in the language standard. Common Lisp provides the building blocks (OPEN
, CLOSE
, UNWIND-PROTECT
) and the macro WITH-OPEN-FILE
, which expands into code that uses the building blocks.
The drawback is that the body could be long and then the parameters are way at the bottom:
(call-with-open-file
(lambda (s)
(princ 99 s)
; 100 more lines here
)
"dump"
:direction :output)
Thus the macro version is seen as more readable in code, since all the information about the opened stream is located at the top. Note that putting the function at the end and the other parameters at the top would also not be a good option, since in Common Lisp lambda lists we have this: positional parameters come first, then optional and keyword parameters.
But in many libraries one gets both the function and the macro. The macro just expands into the function.
Upvotes: 6