The Common Lisp Hyperspec states "Macro forms cannot expand into declarations; declare expressions must appear as actual subexpressions of the form to which they refer."
I'm confused on the meaning of "expand into". A macro such as the following won't work for obvious reasons:
(defmacro optimize-fully ()
`(declare (optimize (speed 3) (safety 0))))
But what if the macro expansion merely contains a (declare ...) expression?
(defmacro defun-optimized (name (&rest lambda-list) &rest body)
`(defun ,name ,lambda-list
(declare (optimize (speed 3) (safety 0)))
,#body))
(defun-optimized foobar (a b)
(* a b))
Is this a violation of the spec? The CL implementation I use, SBCL, does not complain, and in fact, the macro above seems to work precisely as expected. What gives?
Your first example is exactly what it's prohibiting. You couldn't have code like that combined with something like this:
(defun optimized (a b)
(optimize-fully)
(+ a b))
I sometimes see code like this, though:
(defvar *optimization-settings* '(optimize (speed 3) (safety 0)))
(defun foo (a b)
(declare #.*optimization-settings*)
...)
Related
I'm trying to create a macro (bar) that should be used like this:
(let ((my-var "foo"))
(bar ("some")
:buzz (lambda () (format t "~a~%" my-var))))
The macro should basically just FUNCALL the lambda with taking MY-VAR into account.
What I've come up with is this:
(defmacro bar ((thing) &body body)
`(funcall (coerce (getf (list ,#body) :buzz) 'function)))
This works, it prints "foo".
But I'd like to know if this is how this is done or if there is a better way of doing this.
Well, for a start if you don't need the extra, unused argument, then this is just funcall, since (lambda ...) denotes a function.
(let ((my-var "foo"))
(funcall (lambda () (format t "~a~%" my-var))))
So even if you didn't want to call this funcall you could write it as a function, not a macro: it's not doing any code transformation. But presumably you actually do need this extra argument, and you are intending to use it for some purpose in the expansion, so what you need then is a macro which takes keyword arguments and just expands into a suitable funcall form:
(defmacro bar ((thing) &key (buzz '(lambda ())))
(declare (ignore thing))
`(funcall ,buzz))
What is the fundamental difference in the functions defined using defun and setf as below and is one method preferred over another outside of style considerations?
Using defun:
* (defun myfirst (l)
(car l) )
MYFIRST
* (myfirst '(A B C))
A
Using setf:
* (setf (fdefinition 'myfirst) #'(lambda (l) (car l)))
#<FUNCTION (LAMBDA (L)) {10021B477B}>
* (myfirst '(A B C))
A
If, as according to Wikipedia:
named functions are created by storing a lambda expression in a symbol using the defun macro
Using setf to create a variable in a different way requires the use of funcall:
* (defvar myfirst)
MYFIRST
* (setf myfirst (lambda (l) (car l)))
#<Interpreted Function (LAMBDA (X) (+ X X)) {48035001}>
* (funcall myfirst '(A B C))
A
My understanding is that this type of variable is different than the previous in that this variable is not found in the same namespace as the defun bound symbol as described in Why multiple namespaces?.
First of all, one should never underestimate the importance of style.
We write code not just for computers to run, but, much more importantly, for people to read.
Making code readable and understandable for people is a very important aspect of software development.
Second, yes, there is a big difference between (setf fdefinition) and defun.
The "small" differences are that defun can also set the doc string of the function name (actually, depending on how your imeplementation works, it might do that with lambda also), and creates a named block (seen in the macroexpansions below) which you would otherwise have to create yourself if you want to.
The big difference is that the compiler "knows" about defun and will process it appropriately.
E.g., if your file is
(defun foo (x)
(+ (* x x) x 1))
(defun bar (x)
(+ (foo 1 2 x) x))
then the compiler will probably warn you that you call foo in bar with the wrong number of arguments:
WARNING: in BAR in lines 3..4 : FOO was called with 3 arguments, but it requires 1
argument.
[FOO was defined in lines 1..2 ]
If you replace the defun foo with (setf (fdefinition 'foo) (lambda ...)), the compiler is unlikely to handle it as carefully. Moreover, you will probably get a warning along the lines of
The following functions were used but not defined:
FOO
You might want to examine what defun does in your implementation by macroexpanding it:
(macroexpand-1 '(defun foo (x) "doc" (print x)))
CLISP expands it to
(LET NIL (SYSTEM::REMOVE-OLD-DEFINITIONS 'FOO)
(SYSTEM::EVAL-WHEN-COMPILE
(SYSTEM::C-DEFUN 'FOO (SYSTEM::LAMBDA-LIST-TO-SIGNATURE '(X))))
(SYSTEM::%PUTD 'FOO
(FUNCTION FOO
(LAMBDA (X) "doc" (DECLARE (SYSTEM::IN-DEFUN FOO)) (BLOCK FOO (PRINT X)))))
(EVAL-WHEN (EVAL)
(SYSTEM::%PUT 'FOO 'SYSTEM::DEFINITION
(CONS '(DEFUN FOO (X) "doc" (PRINT X)) (THE-ENVIRONMENT))))
'FOO)
SBCL does:
(PROGN
(EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN 'FOO NIL T))
(SB-IMPL::%DEFUN 'FOO
(SB-INT:NAMED-LAMBDA FOO
(X)
"doc"
(BLOCK FOO (PRINT X)))
(SB-C:SOURCE-LOCATION)))
The point here is that defun has a lot "under the hood", and for a reason. setf fdefinition is, on the other hand, more of "what you see is what you get", i.e., no magic involved.
This does not mean that setf fdefinition has no place in a modern lisp codebase. You can use it, e.g., to implement a "poor man's trace" (UNTESTED):
(defun trace (symbol)
(setf (get symbol 'old-def) (fdefinition symbol)
(fdefinition symbol)
(lambda (&rest args)
(print (cons symbol args))
(apply (get symbol 'old-def) args))))
(defun untrace (symbol)
(setf (fdefinition symbol) (get symbol 'old-def))
(remprop symbol 'odd-def))
Assume that the macro would take the boolean types a and b . If a is nil, then the macro should return nil (without ever evaluating b), otherwise it returns b. How do you do this?
This really depends on what you can use.
E.g., is or available? if? cond?
Here is one example:
(defmacro and (a b)
`(if ,a ,b nil)
EDIT. In response to a comment, or is more complicated because we have to avoid double evaluation:
(defmacro or (a b)
(let ((v (gensym "OR")))
`(let ((,v ,a))
(if ,v ,v ,b))))
sds's answer is nice and concise, but it has two limitations:
It only works with two arguments, whereas the built in and and or take any number of arguments. It's not too hard to update the solution to take any number of arguments, but it would be a bit more complicated.
More importantly, it's based very directly in terms of delayed operations that are already present in the language. I.e., it takes advantage of the fact that if doesn't evaluate the then or else parts until it has first evaluated the condition.
It might be a good exercise, then, to note that when a macro needs to delay evaluation of some forms, it's often the simplest strategy (in terms of implementation, but not necessarily the most efficient) to use a macro that expands to a function call that takes a function. For instance, a naive implementation of with-open-file might be:
(defun %call-with-open-file (pathname function)
(funcall function (open pathname)))
(defmacro my-with-open-file ((var pathname) &body body)
`(%call-with-open-file
,pathname
(lambda (,var)
,#body)))
Using a technique like this, you can easily get a binary and (and or):
(defun %and (a b)
(if (funcall a)
(funcall b)
nil))
(defmacro my-and (a b)
`(%and (lambda () ,a)
(lambda () ,b)))
CL-USER> (my-and t (print "hello"))
"hello" ; printed output
"hello" ; return value
CL-USER> (my-and nil (print "hello"))
NIL
or is similar:
(defun %or (a b)
(let ((aa (funcall a)))
(if aa
aa
(funcall b))))
(defmacro my-or (a b)
`(%or (lambda () ,a)
(lambda () ,b)))
To handle the n-ary case (since and and or actually take any number of arguments), you could write a function that takes a list of lambda functions and calls each of them until you get to one that would short circuit (or else reaches the end). Common Lisp actually already has functions like that: every and some. With this approach, you could implement and in terms of every by wrapping all the arguments in lambda functions:
(defmacro my-and (&rest args)
`(every #'funcall
(list ,#(mapcar #'(lambda (form)
`(lambda () ,form))
args))))
For instance, with this implementation,
(my-and (listp '()) (evenp 3) (null 'x))
expands to:
(EVERY #'FUNCALL
(LIST (LAMBDA () (LISTP 'NIL))
(LAMBDA () (EVENP 3))
(LAMBDA () (NULL 'X))))
Since all the forms are now wrapped in lambda functions, they won't get called until every gets that far.
The only difference is that and is specially defined to return the value of the last argument if all the preceding ones are true (e.g., (and t t 3) returns 3, not t, whereas the specific return value of every is not specified (except that it would be a true value).
With this approach, implementing or (using some) is no more complicated than implementing and:
(defmacro my-or (&rest args)
`(some #'funcall ,#(mapcar #'(lambda (form)
`(lambda () ,form))
args)))
I was working with common lisp, and found myself typing up slot definitions of the following form quite a lot:
(name :initarg :name :accessor name)
And so I thought to concoct a macro to speed up this. I came up with the following:
(defmacro quickslot (name)
`(,name :initarg ,(intern (string-upcase name) "KEYWORD") :accessor ,name))
A dirty hack, no doubt, but functional. Or so I thought. When I tried to run my code, I cam across a snag: since defclass is a macro, the arguments are passed to it unevaluated. That means, instead of seeing
(x :initarg :x :accessor x)
It sees
(quickslot x)
Which, of course, signals an error.
The answer, it seems to me, would be to somehow control the order of macro expansion in order to make sure quickslot is expanded before defclass. Which brings me to my question: how would one accomplish this? Or, if you have a different solution to my initial conundrum, that would not go unappreciated either.
That's not really worthy of a macro. Macros typically take literal Lisp source code as their input.
Instead you could just use a function. From Practical Common Lisp, Ch.24:
(defun as-keyword (sym) (intern (string sym) :keyword))
(defun slot->defclass-slot (spec)
(let ((name (first spec)))
`(,name :initarg ,(as-keyword name) :accessor ,name)))
Then you could do something like (again adapted from PCL):
(defmacro my-defclass (name slots)
`(defclass ,name ()
,(mapcar #'slot->defclass-slot slots)))
No, you can't do it. You could write a macro around defclass instead though (that has some special syntax for your quickslots).
You could approach the problem entirely differently and come up with a reader-macro that instructs the reader to call macroexpand on the code that follows it, that would be more generic then just the one purpose for slots declaration in the class. But the complete solution would be somewhat involved, because you'd had to account for many peculiarities and demands of the reader, however, even something as ugly as this would do the job:
(defmacro quickslot (name)
`(,name :initarg ,(intern (string-upcase name) "KEYWORD") :accessor ,name))
(macroexpand '(defclass test-class ()
(#.(macroexpand '(quickslot some-slot)))))
So, what you'd have to do would be something like an alias to #.(macroexpand ...)
And... here you go:
(set-macro-character
#\{
#'(lambda (str char)
(declare (ignore char))
(let ((*readtable* (copy-readtable *readtable* nil))
(reading-p t))
(set-macro-character
#\}
#'(lambda (stream char)
(declare (ignore char stream))
(setf reading-p nil)))
(loop for exp = (read str nil nil t)
while reading-p
collect (macroexpand exp)))))
(read-from-string "'(defclass test-class ()
{(quickslot some-slot)
(quickslot some-other-slot)})")
'(DEFCLASS TEST-CLASS NIL
((SOME-SLOT :INITARG :SOME-SLOT :ACCESSOR SOME-SLOT)
(SOME-OTHER-SLOT :INITARG :SOME-OTHER-SLOT :ACCESSOR
SOME-OTHER-SLOT)))
:)
I'm trying to write a macro in Lisp that re-implements let using itself. This is a trivial exercise which has no practical purpose; however after giving a response to a related question, I realized I should probably learn more about macros. They're touted as one of the great things about Lisp, but I rarely use them.
Anyway, here's what I tried first:
(defmacro mylet (args &rest exp) `(let ,args (dolist (x ,exp) x)))
but when I try something like:
(mylet ((a 5) (b 2)) (print (+ a b)))
this throws up an error:
#1=(PRINT (+ A B)) is not a symbol or lambda expression in the form (#1#) .
args (a and b) are set properly, but the print statement doesn't work. I think it's because I'm using two levels of indirection-- referring to a variable that I've created within the macro. But I can't seem to figure out how to fix it! Any ideas?
Your macro expands to:
(LET ((A 5) (B 2))
(DOLIST (X ((PRINT (+ A B)))) X))
which is invalid because ((PRINT (+ A B))) is not a valid expression. There is also an issue that using an interned symbol in macro expansion can lead to variable capture, but that is not directly relevant (read more in PCL).
Using DOLIST here is unnecessary, and compilcated to get right (you would have to convert all subforms to anonymous function in order to stick them in a list, funcall them in sequence and then store the final result in order to conform to PROGN behaviour). You can just use PROGN, or, since LET includes an implicit PROGN, just splice the body using the ,# feature of backquote mechanism:
(defmacro mylet (args &body exp) `(let ,args ,(cons 'progn exp)))
(defmacro mylet (args &body exp) `(let ,args ,#exp))