2015-03-12 3 views
0

Я использую общий lisp со слизью в emacs и пытаюсь определить простой макрос. Однако, когда я запускаю макрос, буфер слизи emacs становится невосприимчивым, и мой компьютер быстро становится непригодным. Даже после выхода из emacs я получаю сообщения об ошибках в сообщении bash о невозможности выделения памяти.LISP macro fail, crashes slime

Я хочу использовать макрос, чтобы писать такие функции, как эти два

(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))) 

используя синтаксис как

(defchord 'mtriad '(1 3 5)) 
(defchord 'mquad '(1 3 5 7)) 

Я решил использовать MAPCAR и лямбда-функции для генерации выходного сигнала я хочу , На переводчике, это работает для генерации я хочу:

CL-USER> (mapcar (lambda (x) `(%part (+ ,x 2) scale)) '(1 3 5)) 
((%PART (+ 1 2) SCALE) (%PART (+ 3 2) SCALE) (%PART (+ 5 2) SCALE)) 

Однако, когда я пытаюсь поставить его внутри макроса, чтобы произвести вызов Defun, он выходит из строя слизи и убивает мою память, как только я называю это:

(defmacro defchord (name steps) 
    `(defun ,name (foo scale) 
    (quote ,(mapcar (lambda (x) `(%part (+ ,x 2) scale)) steps)))) 

Я надеюсь, что это простая ошибка новобранец!

ответ

1

Вот моя реализация макроса, который генерирует функции, которые первоначально перечисленных:

(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)))) 

Некоторые примеры:

> (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))) 

Это выглядит как довольно хороший матч для функций, которые вы перечислили, я думаю, , :-)

+0

Красивая, это именно то, что мне нужно. Что делает период до создания карты? Я замечаю, что цитаты внутри цитат здесь, хотя другой плакат, казалось, подразумевал, что это была моя оригинальная проблема. – jimpudar

+1

1. ', .' является неприемлемой версией', @ '(unquote-splicing). Он используется для списков, которые недавно созданы (например, «mapcar», в этом случае), которые, как вы знаете, могут быть изменены на месте. Если есть сомнения, просто используйте ', @', что всегда безопасно. 2. Нет, вы все еще не можете использовать цитату здесь, и, в частности, вы не можете просто процитировать «триаду» или «квадрат» или списки шагов. –

2

Вы цитируете внутреннюю цитату, и вы цитируете свои аргументы, как если бы они были функциями. Если это приемлемо, вы можете просто сделать его функцией:

(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)) 
+0

Спасибо за помощь. Неправильно ли цитировать внутри цитаты? – jimpudar

+1

@jimpudar, когда вы что-то цитируете, '' mtriad', это то же самое, что писать '(quote mtriad)'. Макрос не оценивает его аргументы, поэтому ваш аргумент представляет собой список с двумя символами 'quote' и' mtriad' и как вы использовали этот список для использования в качестве имени: '(defun (quote mtriad) (foo scale) ...) '. Ваше тело макроса использует quoasiquoting, и вы используете цитату внутри нее. – Sylwester

Смежные вопросы