Ошибка макроса LISP, вылетает слизь

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

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

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

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


person jimpudar    schedule 12.03.2015    source источник


Ответы (2)


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

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

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

person Chris Jester-Young    schedule 12.03.2015
comment
Красиво, это именно то, что мне нужно. Что делает период до mapcar? Я заметил здесь цитирование внутри цитат, хотя другой плакат, казалось, подразумевал, что это была моя первоначальная проблема. - person jimpudar; 13.03.2015
comment
1. ,. - это несостоящая версия ,@ (без кавычек). Он используется для недавно созданных списков (например, mapcar в данном случае), которые, как вы знаете, могут быть изменены на месте. Если сомневаетесь, просто используйте ,@, что всегда безопасно. 2. Нет, вы по-прежнему не можете использовать здесь цитирование, в частности, вы не можете цитировать triad или quad или списки шагов. - person Chris Jester-Young; 13.03.2015

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

(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))
person Sylwester    schedule 12.03.2015
comment
Спасибо за помощь. это неправильно цитировать внутри цитаты ?? - person jimpudar; 13.03.2015
comment
@jimpudar, когда вы что-то цитируете, 'mtriad, это то же самое, что писать (quote mtriad). Макрос не оценивает свои аргументы, поэтому ваш аргумент представляет собой список с двумя символами quote и mtriad, и то, как вы использовали этот список, заключалось в использовании его в качестве имени: (defun (quote mtriad) (foo scale) ...). Ваше тело макроса использует кавычки, а вы используете кавычки внутри него. - person Sylwester; 13.03.2015