Given the macro:
(defclass sample-class ()
((slot-1 :accessor slot-1
:initform "sample slot")))
(defvar *sample-instance*(make-instance 'sample-class))
(defmacro sample-macro (p)
`(if (typep ,p 'sample-class)
(progn
(print "evaluated")
(print ,(slot-1 p)))))
(sample-macro *sample-instance*)
I am confused as to why this is the error output
Execution of a form compiled with errors.
Form:
(SAMPLE-MACRO *SAMPLE-INSTANCE*)
Compile-time error:
(during macroexpansion of (SAMPLE-MACRO *SAMPLE-INSTANCE*))
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::SLOT-1 (1)>
when called with arguments
(*SAMPLE-INSTANCE*).
See also:
The ANSI Standard, Section 7.6.6
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
Shouldn't the macro expand and evaluate the s-form in the process? Why is the reader not finding the generic function slot-1?
I think you are confused about what macros do. Macros are transformations of source code. So consider what happens when the system tries to expand the macro form (sample-macro *sample-instance*). At macroexpansion time, p is the symbol *sample-instance*: a representation of a bit of source code.
So now, look at the backquoted form in the body of the macro: in it there is ,(slot-1 p): this will try and call slot-1 on whatever p is bound to, which is a symbol. This then fails and the macroexpansion fails as a result.
Well, you could 'fix' this in a way which seems obvious:
(defmacro sample-macro (p)
`(if (typep ,p 'sample-class)
(progn
(print "evaluated")
(print (slot-1 ,p)))))
And this seems to work. Using a macroexpansion tracer:
(sample-macro *sample-instance*)
-> (if (typep *sample-instance* 'sample-class)
(progn (print "evaluated") (print (slot-1 *sample-instance*))))
And if you use the macro it will 'work'. Except it won't work, at all: Consider this form: (sample-macro (make-instance 'sample-class)): well, let's look at that using the macro tracer:
(sample-macro (make-instance 'sample-class))
-> (if (typep (make-instance 'sample-class) 'sample-class)
(progn
(print "evaluated")
(print (slot-1 (make-instance 'sample-class)))))
Oh dear.
So we could work around this problem by rewriting the macro like this:
(defmacro sample-macro (p)
`(let ((it ,p))
(if (typep it 'sample-class)
(progn
(print "evaluated")
(print (slot-1 it)))
And now
(sample-macro (make-instance 'sample-class))
-> (let ((it (make-instance 'sample-class)))
(if (typep it 'sample-class)
(progn (print "evaluated") (print (slot-1 it)))))
Which is better. And in this case it's even safe, but in the great majority of cases we'd need to use a gensym for the thing I've called it:
(defmacro sample-macro (p)
(let ((itn (make-symbol "IT"))) ;not needed for this macro
`(let ((,itn ,p))
(if (typep ,itn 'sample-class)
(progn
(print "evaluated")
(print (slot-1 ,itn)))))))
And now:
(sample-macro (make-instance 'sample-class))
-> (let ((#:it (make-instance 'sample-class)))
(if (typep #:it 'sample-class)
(progn (print "evaluated") (print (slot-1 #:it)))))
So this (and in fact the previous version of it as well) is finally working.
But wait, but wait. What we've done is to turn this thing into something which:
binds the value of its argument to a variable;
and evaluates some code with that binding.
There's a name for something which does that, and that name is function.
(defun not-sample-macro-any-more (it)
(if (typep it 'sample-class)
(progn
(print "evaluated")
(print (slot-1 it)))))
This does everything that the working versions of sample-macro did but without all the needless complexity.
Well, it doesn't do one thing: it doesn't get expanded inline, and perhaps that means it might be a little slower.
Well, back in the days of coal-fired Lisp this was a real problem. Coal-fired Lisp systems had primitive compilers made of wood shavings and sawdust and ran on computers which were very slow indeed. So people would write things which should semantically be functions as macros so the wood-shaving compiler would inline the code. And sometimes this was even worth it.
But now we have advanced compilers (probably still mostly made of wood shavings and sawdust though) and we can say what we actually mean:
(declaim (inline not-sample-macro-any-more))
(defun not-sample-macro-any-more (it)
(if (typep it 'sample-class)
(progn
(print "evaluated")
(print (slot-1 it)))))
And now you can be reasonably assured that not-sample-macro-any-more will be compiled inline.
Even better in this case (but at the cost of almost certainly not having the inlining stuff):
(defgeneric not-even-slightly-sample-macro (it)
(:method (it)
(declare (ignore it))
nil))
(defmethod not-even-slightly-sample-macro ((it sample-class))
(print "evaluated")
(print (slot-1 it)))
So the summary here is:
Use macros for what they are for, which is transforming source code. If you don't want to do that, use functions. If you are sure the that the act of calling the functions is taking up lots of time, then consider declaring them inline to avoid that.
The other answers explained that macro execution is about transforming source code and values available at macro expansion time.
Let's also try to understand the error message. We need to take it literally:
Execution of a form compiled with errors.
Above says that it is about compilation.
Form:
(SAMPLE-MACRO *SAMPLE-INSTANCE*)
Above is the source form which is to be compiled.
Compile-time error:
(during macroexpansion of (SAMPLE-MACRO *SAMPLE-INSTANCE*))
Again: compilation and now specifically during macro expansion.
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::SLOT-1 (1)>
when called with arguments
(*SAMPLE-INSTANCE*).
Now above is the interesting part: there is no applicable method for the generic function SLOT-1 and the argument *SAMPLE-INSTANCE*.
What is *SAMPLE-INSTANCE*? It's a symbol. In your code is a method, but it is for instances of class sample-class. But there is no method for symbols. So this will not work:
(setf p '*sample-instance*)
(slot-1 p)
That's basically what your code did. You expected to work with runtime values, but all you got at compile time was a source symbol...
The compiler error message showing a compile time error with a source-code element is an indication that there is mixup of runtime and macro-expansion time computation.
See also:
The ANSI Standard, Section 7.6.6
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
To understand what the macro is doing, let's use macroexpand.
(macroexpand-1 '(sample-macro *sample-instance*))
=>
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION COMMON-LISP-USER::SLOT-1 (1)>
when called with arguments
(*SAMPLE-INSTANCE*).
[Condition of type SB-PCL::NO-APPLICABLE-METHOD-ERROR]
Oops, same error message. I will simplify the macro and remove the evaluation around slot-1.
(defmacro sample-macro (p)
`(if (typep ,p 'sample-class)
(progn
(print "evaluated")
(print (slot-1 p)))))
(macroexpand-1 '(sample-macro *sample-instance*))
=>
(IF (TYPEP *SAMPLE-INSTANCE* 'SAMPLE-CLASS)
(PROGN (PRINT "evaluated") (PRINT (SLOT-1 P))))
The code looks good until the variable P. So will it work with, simply, ,p? No need to write ,(slot-1 p) since slot-1 is here correctly.
(defmacro sample-macro (p)
`(if (typep ,p 'sample-class)
(progn
(print "evaluated")
(print (slot-1 ,p)))))
(macroexpand-1 '(sample-macro *sample-instance*))
=>
(IF (TYPEP *SAMPLE-INSTANCE* 'SAMPLE-CLASS)
(PROGN (PRINT "evaluated") (PRINT (SLOT-1 *SAMPLE-INSTANCE*))))
The code looks correct.
(sample-macro *sample-instance*)
"evaluated"
"sample slot"
and it works.
Related
Common Lisp built-in functions are probably implemented in C. But I imagine macros are implemented in lisp (sorry if I'm wrong about any of two sentences). Is there any way (through some function or some macro) to see the implementations of built-in macros in Common Lisp? I'm using CLisp.
The ability to inspect function and macro definitions is a feature of your development environment. These days it is typical to use SLIME or SLY with emacs as the basis of a Lisp development environment. I personally use SLIME, but I have heard good things about SLY, too.
In SLIME you can invoke slime-edit-definition (either by keying M-x slime-edit-definition or by using the keybinding M-.) to visit a definition for the symbol under the cursor in a source file. This works both when editing in a source file, or from the REPL. This feature is extremely useful when you want to inspect some library code you are working with, but you can also view a lot of built-in definitions this way. You can even jump to a new definition from a new symbol found in whatever definition you are currently inspecting.
After you are done looking at a definition, you can use M-x slime-pop-find-definition-stack, or the easier to remember keybinding M-, (M-* will also work), to back out through the previously viewed definitions, eventually returning to your starting point.
Here is an example, in SBCL:
CL-USER> with-open-file[press M-.]
(Note that the "[press M-.]" above is not typed, but only meant to remind what action is taken here). With the cursor on or right after the symbol with-open-file, press M-. to see the definition:
(sb-xc:defmacro with-open-file ((stream filespec &rest options)
&body body)
(multiple-value-bind (forms decls) (parse-body body nil)
(let ((abortp (gensym)))
`(let ((,stream (open ,filespec ,#options))
(,abortp t))
,#decls
(unwind-protect
(multiple-value-prog1
(progn ,#forms)
(setq ,abortp nil))
(when ,stream
(close ,stream :abort ,abortp)))))))
This time after keying M-. SLIME gives a choice of definitions to view:
CL-USER> and[press M-.]
Displayed in an emacs buffer:
/path-to-source/sbcl-2.0.4/src/code/macros.lisp
(DEFMACRO AND)
/path-to-source/sbcl-2.0.4/src/pcl/ctypes.lisp
(DEFINE-METHOD-COMBINATION AND)
We want to see the macro definition, so move the cursor to the line showing (DEFMACRO AND), and the following definition is displayed:
;; AND and OR are defined in terms of IF.
(sb-xc:defmacro and (&rest forms)
(named-let expand-forms ((nested nil) (forms forms) (ignore-last nil))
(cond ((endp forms) t)
((endp (rest forms))
(let ((car (car forms)))
(cond (nested
car)
(t
;; Preserve non-toplevelness of the form!
`(the t ,car)))))
((and ignore-last
(endp (cddr forms)))
(car forms))
;; Better code that way, since the result will only have two
;; values, NIL or the last form, and the precedeing tests
;; will only be used for jumps
((and (not nested) (cddr forms))
`(if ,(expand-forms t forms t)
,#(last forms)))
(t
`(if ,(first forms)
,(expand-forms t (rest forms) ignore-last))))))
There is more stuff here, since you are now actually in the source file that contains the definition for and; if you scroll down a bit you can also find the definition for or.
A lot of SBCL functions are written in Lisp; SBCL has a very high-quality compiler, so a lot of stuff that you might otherwise expect to be written in C can be written in Lisp without loss of performance. Here is the definition for the function list-length:
CL-USER> list-length[press M-.]
(defun list-length (list)
"Return the length of the given List, or Nil if the List is circular."
(do ((n 0 (+ n 2))
(y list (cddr y))
(z list (cdr z)))
(())
(declare (type fixnum n)
(type list y z))
(when (endp y) (return n))
(when (endp (cdr y)) (return (+ n 1)))
(when (and (eq y z) (> n 0)) (return nil))))
The same thing can be done when using CLISP with SLIME. Here is with-open-file as defined in CLISP:
CL-USER> with-open-file[press M-.]
(defmacro with-open-file ((stream &rest options) &body body)
(multiple-value-bind (body-rest declarations) (SYSTEM::PARSE-BODY body)
`(LET ((,stream (OPEN ,#options)))
(DECLARE (READ-ONLY ,stream) ,#declarations)
(UNWIND-PROTECT
(MULTIPLE-VALUE-PROG1
(PROGN ,#body-rest)
;; Why do we do a first CLOSE invocation inside the protected form?
;; For reliability: Because the stream may be a buffered file stream,
;; therefore (CLOSE ,stream) may produce a disk-full error while
;; writing the last block of the file. In this case, we need to erase
;; the file again, through a (CLOSE ,stream :ABORT T) invocation.
(WHEN ,stream (CLOSE ,stream)))
(WHEN ,stream (CLOSE ,stream :ABORT T))))))
But, many CLISP functions are written in C, and those definitions are not available to inspect in the same way as before:
CL-USER> list-length[press M-.]
No known definition for: list-length (in COMMON-LISP-USER)
I'm trying to create something similar to with-eval-after-load except that the body evaluates after all features have been provided. Additionally, the feature list must be provided at runtime.
For example, I want something like
(setq feature-list '(a b))
(something feature-list (message "a and b both provided"))
where this performs functionality equivalent to
(with-eval-after-load 'a
(with-eval-after-load 'b
(message "a and b both provided")))
Providing the list at runtime seems to be the tricky part. Without that requirement I could write a macro:
(defmacro eval-after-load-all (features body)
(if (null features)
body
`(with-eval-after-load (quote ,(car features))
(eval-after-load-all ,(cdr features) ,body))))
and pass the list with:
(eval-after-load-all (a b) (message "a and b both provided"))
But passing it feature-list will cause it to use the literal characters "feature-list".
I've tried defining a recursive function:
(defun eval-after-load-all (features body)
(if (null features)
body
(with-eval-after-load (car features)
(eval-after-load-all (cdr features) body))))
But when I evaluate
(eval-after-load-all feature-list (message "a and b both provided"))
(provide 'a)
;; (provide 'b)
It triggers an error at the (provide 'a) call complaining about void-variable body in the recursive call step (i.e. last expression in the function). This scope confuses me. Why is body void here?
I also tried to wrap the macro in a function so that I could pass it the evaluated arguments:
(defun macro-wrapper (features body)
(eval-after-load-all features body))
but this complains at function definition that features is not a list: wrong-type-argument listp features.
You may not use the symbol features as an argument since that is (I cite the doc of features):
A list of symbols which are the features of the executing Emacs.
Used by featurep and require, and altered by provide.
The following code for eval-after-load-all works as expected. It is derived from your recursive function definition.
I added the evaluation of the form as function or as expression with funcall or eval, respectively, I used the backquote for the lambda, and I introduced the quoting for the list and the expression in the generated lambda expression.
(defun eval-after-load-all (my-features form)
"Run FORM after all MY-FEATURES are loaded.
See `eval-after-load' for the possible formats of FORM."
(if (null my-features)
(if (functionp form)
(funcall form)
(eval form))
(eval-after-load (car my-features)
`(lambda ()
(eval-after-load-all
(quote ,(cdr my-features))
(quote ,form))))))
I have some questions about how macros work in Scheme (specifically in Chicken Scheme), let's consider this example:
(define (when-a condition . body)
(eval `(if ,condition
(begin ,#body)
'())))
(define-syntax when-b
(er-macro-transformer
(lambda (exp rename compare)
(let ((condition (cadr exp))
(body (cddr exp)))
`(if ,condition (begin ,#body) '())))))
(define-syntax when-c
(ir-macro-transformer
(lambda (exp inject compare)
(let ((condition (cadr exp))
(body (cddr exp)))
`(if ,condition (begin ,#body) '())))))
(define-syntax when-d
(syntax-rules ()
((when condition body ...)
(if condition (begin body ...) '()))))
Can I consider when-a a macro? I feel that I can't consider it a macro in a strict way since I'm not using define-syntax but I'm not able to say any pratical reason to not prefer this implementation.
Are my macros hygienic?
Is there any difference between when-b and when-c? Since I'm not using rename nor inject I think there isn't.
Can I consider when-a a macro? I feel that I can't consider it a macro in a strict way since I'm not using define-syntax but I'm not able to say any pratical reason to not prefer this implementation.
This works like a macro, but it's not exactly the same as a true macro, for the following reasons:
The main difference between a true macro and your eval-based "macro" is that your approach will evaluate all its arguments before calling it. This is a very important difference. For example: (if #f (error "oops") '()) will evaluate to '() but (when-a #f (error "oops")) will raise an error.
It's not hygienic. Beforehand, one might have done something like (eval '(define if "not a procedure")), for example, and that would mean this eval would fail; the if in the body expression of the "expansion" doesn't refer to the if at the definition site.
It does not get expanded at compile time. This is another major reason to use a macro; the compiler will expand it, and at runtime no computation will be performed to perform the expansion. The macro itself will have completely evaporated. Only the expansion remains.
Are my macros hygienic?
Only when-c and when-d are, because of the guarantees made by ir-macro-transformer and syntax-rules. In when-b you'd have to rename if and begin to make them refer to the versions of if and begin at the macro definition site.
Example:
(let ((if #f))
(when-b #t (print "Yeah, ok")))
== expands to ==>
(let ((if1 #f))
(if1 #t (begin1 (print "Yeah, ok"))))
This will fail, because both versions of if (here annotated with an extra 1 suffix) refer to the same thing, so we'll end up calling #f in operator position.
In contrast,
(let ((if #f))
(when-c #t (print "Yeah, ok")))
== expands to ==>
(let ((if1 #f))
(if2 #t (begin1 (print "Yeah, ok"))))
Which will work as intended. If you want to rewrite when-b to be hygienic, do it like this:
(define-syntax when-b
(er-macro-transformer
(lambda (exp rename compare)
(let ((condition (cadr exp))
(body (cddr exp))
(%if (rename 'if))
(%begin (rename 'begin)))
`(,%if ,condition (,%begin ,#body) '())))))
Note the extra %-prefixed identifiers which refer to the original value of if and begin as they were at the place of definition of the macro.
Is there any difference between when-b and when-c? Since I'm not using rename nor inject I think there isn't.
There is. Implicit renaming macros are called that because they implicitly rename all the identifiers that come in from the usage site, and also every new identifier you introduce in the body. If you inject any identifiers, that undoes this implicit renaming, which makes them unhygienically available for capture by the calling code.
On the other hand, explicit renaming macros are called that because you must explicitly rename any identifiers to prevent them being captured by the calling code.
I'd like to learn more about lisp macros and I want to create a simple implementation of the defun macro.
I'm also interested in lisp's source code in all the implementations.
This is a tricky question, because of bootstrapping: defun does a lot of things (iow, calls a lot of functions), but to define those functions one needs a working defun. Thus there are three(3!) definitions of defun in clisp/src/init.lisp: at lines
228
1789
1946
The very basic definition of defun could be this:
(defmacro defun (fname lambda-list &rest body)
`(setf (fdefinition ',fname)
(lambda ,lambda-list
(block ,fname ,#body))))
In fact, this is the first definition of defun in CLISP (line 228), except that there is no defmacro and no backquote at that moment yet, so the actual code looks a lot uglier.
See also Is defun or setf preferred for creating function definitions in common lisp and why? where I discuss macroexpansions of defuns.
You can easily check how your particular CL implementation, implemented defun by running
(macroexpand '(defun add2 (x) (+ x 2)))
On SBCL it expands to:
(PROGN
(EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN 'ADD2 NIL T))
(SB-IMPL::%DEFUN 'ADD2
(SB-INT:NAMED-LAMBDA ADD2
(X)
(BLOCK ADD2 (+ X 2)))
(SB-C:SOURCE-LOCATION)))
T
To see the particular source code that implemented the I would use (on Emacs) the M-. key binding and then I will write defun and hit enter. Then Emacs will get to the source code:
(sb!xc:defmacro defun (&environment env name lambda-list &body body)
#!+sb-doc
"Define a function at top level."
[...]
I am not going to paste the whole macro as it is rather long. If you are not on Emacs, you can try searching in the repos as most implementations are open source.
BTW defun is not so special. You can implement much of it with setf-inf a symbol-function to a lambda. E.g.:
(setf (symbol-function 'ADD3) #'(lambda (x) (+ x 3)))
; => #<FUNCTION (LAMBDA (X)) {1006E94EBB}>
(add3 4)
; => 7
I've got another question involving self-reference in Common Lisp. I found a thread on Stack Exchange which poses a problem of writing the shortest program that would print all printable ASCII characters NOT present in the program's source code. This got me thinking how to tackle the problem in Common Lisp. I hit against two problems - one probably trivial, the other more tricky:
First is the case of writing a CL script, e.g. starting with #!/usr/bin/env sbcl --script. I thought that through *posix-argv* I could access all command line arguments including the name of the called script. I also looked for the equivalent of Bash $0 but could find none. What worked for me in the end is this ugly Bash-ified SBCL script, which explicitly passes $0 to SBCL and proceeds from that:
#!/bin/bash
#|
sbcl --script $0 $0
exit
|#
(defun file-string (path)
(with-open-file (stream path)
(let ((data (make-string (file-length stream))))
(read-sequence data stream)
data)))
(let* ((printable (mapcar #'code-char (loop for i from #x20 to #x7e collect i)))
(absent (set-difference
printable
(coerce (file-string (cadr *posix-argv*)) 'list))))
(print (coerce absent 'string)))
My question regarding this point is: can you think of any way of doing it without relying so heavily on Bash supplying relevant arguments? Or, more briefly: is there a CL (SBCL in particular) equivalent of $0?
Now comes the part that I'm totally puzzled with. Before resorting to the script approach above I tried to accomplish this goal in a more REPL-oriented way. Based on the &whole specifier in defmacro and considerations in this thread I've tried to get the name of the macro from the &whole argument and somehow "read in" its source. And I have absolutely no idea how to do it. So in short: given the name of the macro, can I somehow obtain the defmacro form which defined it? And I'm talking about a generic solution, rather than parsing the REPL history.
EDIT: Regarding mbratch's question about use of macroexpand-1 here's how I do it:
(defmacro self-refer (&whole body)
(macroexpand-1 `',body))
With this call I'm able to obtain (SELF-REFER) by calling (SELF-REFER). Which isn't much of a solution...
I hope someone could point me in the right direction. Thanks!
Getting the source of a macro is not defined in Common Lisp.
This may work (Example from LispWorks):
CL-USER 10 > (defmacro foo (a b) `(* (+ ,a ,b) (+ ,a ,a)))
FOO
CL-USER 11 > (pprint (function-lambda-expression (macro-function 'foo)))
(LAMBDA
(DSPEC::%%MACROARG%% #:&ENVIRONMENT1106 &AUX (#:&WHOLE1107 DSPEC::%%MACROARG%%)
(#:\(A\ ...\)1108 (CDR #:&WHOLE1107))
(#:CHECK-LAMBDA-LIST-TOP-LEVEL1110
(DSPEC::CHECK-LAMBDA-LIST-TOP-LEVEL '(A B)
#:&WHOLE1107
#:\(A\ ...\)1108
2
2
'NIL
:MACRO))
(A (CAR (DSPEC::THE-CONS #:\(A\ ...\)1108)))
(#:\(B\)1109 (CDR (DSPEC::THE-CONS #:\(A\ ...\)1108)))
(B (CAR (DSPEC::THE-CONS #:\(B\)1109))))
(DECLARE (LAMBDA-LIST A B))
(BLOCK FOO `(* (+ ,A ,B) (+ ,A ,A))))
An even more esoteric way is to alter the existing DEFMACRO to record its source.
Many Lisp implementations have a non-standard feature called advising. LispWorks for example can advise macros:
CL-USER 31 > (defadvice (defmacro source-record-defmacro :after)
(&rest args)
(setf (get (second (first args)) :macro-source) (first args)))
T
Above adds code to the standard DEFMACRO macro, which records the source on the symbol property list of the macro name. defmacro is the name of the thing to advise. source-record-defmacro is the chosen name of this advice. :after then specifies that the code should run after the normal defmacro code.
CL-USER 32 > (defmacro foo (a b) `(* (+ ,a ,b) (+ ,a ,a)))
FOO
CL-USER 33 > (pprint (get 'foo :macro-source))
(DEFMACRO FOO (A B) `(* (+ ,A ,B) (+ ,A ,A)))
Again, this is completely non-standard - I'm not sure if a comparable mechanism exists for SBCL, though it has something called 'encapsulate'.
A very belated followup to Rainer Joswig's LispWorks solution. I've been using Allegro CL lately and discovered the fwrap facility. Conceptually it's very similar to the defadvice above and slighly more verbose. Here's a re-iteration of Rainer's example in ACL 10.0:
(def-fwrapper source-record-defmacro (&rest args)
(setf (get (second (first args)) :macro-source) (first args))
(call-next-fwrapper))
Having defined an fwrapper you need to "put it into action" explicitly:
(fwrap 'defmacro 'srd 'source-record-defmacro)
After this it's like in Rainer's example:
CL-USER> (defmacro foo (a b) `(* (+ ,a ,b) (+ ,a ,a)))
FOO
CL-USER> (pprint (get 'foo :macro-source))
(DEFMACRO FOO (A B) `(* (+ ,A ,B) (+ ,A ,A)))
; No value