Reputation: 309
I am using common lisp with slime in emacs and am trying to define a simple macro. However when I run the macro, the emacs slime buffer becomes unresponsive and my computer quickly becomes unusable. Even after exiting emacs I get error messages at the bash prompt about not being able to allocate memory.
I want to use my macro to write functions such as these two
(defun triad (foo scale)
"Generates a triad on scale-step FOO of scale SCALE"
(list (%part (- foo 1) scale)
(%part (+ foo 1) scale)
(%part (+ foo 3) scale)))
(defun quad (foo scale)
"Generates a quad on scale step FOO of scale SCALE"
(list (%part (- foo 1) scale)
(%part (+ foo 1) scale)
(%part (+ foo 3) scale)
(%part (+ foo 5) scale)))
using a syntax like
(defchord 'mtriad '(1 3 5))
(defchord 'mquad '(1 3 5 7))
I decided to use mapcar and a lambda function to generate the output I want. At the interpreter, this works to generate the I want:
CL-USER> (mapcar (lambda (x) `(%part (+ ,x 2) scale)) '(1 3 5))
((%PART (+ 1 2) SCALE) (%PART (+ 3 2) SCALE) (%PART (+ 5 2) SCALE))
However when I try to put it inside of a macro in order to generate the defun call, it crashes slime and kills my memory as soon as I call it:
(defmacro defchord (name steps)
`(defun ,name (foo scale)
(quote ,(mapcar (lambda (x) `(%part (+ ,x 2) scale)) steps))))
I'm hoping this is a simple rookie mistake!
Upvotes: 0
Views: 116
Reputation: 48735
Your are quoting inside quote and you are quoting your arguments as if they were functions. If that is acceptable you could just make it a function:
(defun defchord (name steps)
(setf (symbol-function name)
(lambda (foo scale)
(mapcar (lambda (step)
(%part (+ foo step) scale))
steps)))
name)
;; test
(defchord 'mtriad '(1 3 5)) ;==> mtriad
(defun %part (x y) (cons x y))
(mtriad 2 10) ; ==> ((3 . 10) (5 . 10) (7 . 10))
Upvotes: 2
Reputation: 222973
Here's my implementation of the macro that generates the functions you initially listed:
(defmacro defchord (name steps)
`(defun ,name (foo scale)
,(concatenate 'string "Generates a " (symbol-name name) " on scale-step FOO of scale SCALE")
(list ,.(mapcar (lambda (i) `(%part (+ foo ,i) scale)) steps))))
Some examples:
> (macroexpand-1 '(defchord triad (-1 1 3)))
(DEFUN TRIAD (FOO SCALE)
"Generates a TRIAD on scale-step FOO of scale SCALE"
(LIST (%PART (+ FOO -1) SCALE) (%PART (+ FOO 1) SCALE)
(%PART (+ FOO 3) SCALE)))
> (macroexpand-1 '(defchord quad (-1 1 3 5)))
(DEFUN QUAD (FOO SCALE)
"Generates a QUAD on scale-step FOO of scale SCALE"
(LIST (%PART (+ FOO -1) SCALE) (%PART (+ FOO 1) SCALE)
(%PART (+ FOO 3) SCALE) (%PART (+ FOO 5) SCALE)))
That looks like a pretty good match for the functions you listed, I think. :-)
Upvotes: 1