jimpudar
jimpudar

Reputation: 309

LISP macro fail, crashes slime

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

Answers (2)

Sylwester
Sylwester

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

C. K. Young
C. K. Young

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

Related Questions