I have the following macro:
(defparameter *current-state* 'foo)
(defmacro when-state ((state &key (test #'eq)) &body body)
`(when (funcall ,test *current-state* ,state)
,@body))
Using it in the REPL it works fine with or without specifying key parameter.
However, when using it in a top-level defun
or lambda
variable declaration, like so:
(defun foo ()
(when-state ('foo)
(format t "Foo")))
Then the file won't compile with SBCL with the following error:
; in: DEFUN FOO
; (SENTO.FSM:WHEN-STATE ('SENTO.FSM::FOO)
; (FORMAT T "Foo"))
; --> IF FUNCALL
; ==>
; 1
;
; caught ERROR:
; Objects of type COMPILED-FUNCTION can't be dumped into fasl files.
;
; note: The first argument never returns a value.
Only when explicitly specifying the key parameter it will compile fine.
What is the problem here?
See the difference:
CL-USER 68 > (macroexpand-1 '(when-state ('foo)
(format t "Foo")))
(WHEN (FUNCALL #<Function EQ 80E003BDE9>
*CURRENT-STATE*
(QUOTE FOO))
(FORMAT T "Foo"))
T
In above generated source code, the function EQ
is included as an object. This can't be dumped.
Now specify the test in the source:
CL-USER 69 > (macroexpand-1 '(when-state ('foo :test #'eq)
(format t "Foo")))
(WHEN (FUNCALL (FUNCTION EQ)
*CURRENT-STATE*
(QUOTE FOO))
(FORMAT T "Foo"))
T
Now quote the test in the WHEN-STATE
definition:
CL-USER 70 > (defmacro when-state ((state &key (test '#'eq)) &body body)
`(when (funcall ,test *current-state* ,state)
,@body))
WHEN-STATE
CL-USER 71 > (macroexpand-1 '(when-state ('foo)
(format t "Foo")))
(WHEN (FUNCALL (FUNCTION EQ)
*CURRENT-STATE*
(QUOTE FOO))
(FORMAT T "Foo"))
T
That looks better...