← Архив: Common Lisp

макросы и синтаксис.

Author: · 06.11.2009 16:19
· original author: tmp.login
есть макрос
(...
 `(...
    ,@(operator
            '(f1)
             ...
            '(fn)
             rest-fns)))
но хочется записать в виде
(...
 `(...
    ,(operator
            f1
             ...
            fn
            (splice-it rest-fns))))
то есть форма operator вычисляется, но только список rest-fns разбивается на элементы.
· original author: archimag
Гм... Из формулироваки вопроса совершенно не понятно, что же на самом деле надо.
Попробую привести пример, который как мне кажется (но с большой вероятностью я ошибаюсь) в чём-то схож с такой задачей
(defmacro sample-macro (&rest fns)
  (let ((fns2 (loop
                 for fn in fns
                 collect (list fn "Hello")
)
)
)

    `(progn
       ,@fns2
)
)
)

(sample-macro print print)
· original author: tmp.login
что-то типа этого, только вместо if несколько случаев.
http://lisper.ru/apps/format/38
· original author: tmp.login
(defmacro prog-nth (nform &body body)
           (flet ((split-forms (forms)
                    (do ((current forms (cdr current))
                         (first-forms) (last-forms)
                         (i 1 (1+ i))
)

                        ((null current) (values (nreverse first-forms) (nreverse last-forms)))
                      (if (< i nform)
                          (push (car current) first-forms)
                          (push (car current) last-forms)
)
)
)
)

             (multiple-value-bind (first-forms last-forms) (split-forms body)
               `(progn
                  ,@first-forms
                  (multiple-value-prog1
                      ,@(if (null last-forms)
                            '(nil)
                            last-forms
)
)
)
)
)
)
· original author: archimag
Ну тогда как-нибудь так:
(defmacro prog-nth (nform &body body)
  (flet ((split-forms (forms)
           (do ((current forms (cdr current))
                (first-forms) (last-forms)
                (i 1 (1+ i))
)

               ((null current) (values (nreverse first-forms) (nreverse last-forms)))
             (if (< i nform)
                 (push (car current) first-forms)
                 (push (car current) last-forms)
)
)
)
)

    (multiple-value-bind (first-forms last-forms) (split-forms body)
      (let ((last-forms2 (calculate-last-forms last-forms))) ;;;;calculate-last-forms - произвольный код
       `(progn
           ,@first-forms
           (multiple-value-prog1
               ,@last-forms2
)
)
)
)
)
)
· original author: tmp.login
тоже самое нужно делать, например, если last-forms nil, то нужно его в список завернуть. вопрос в том, как этого не делать.
· original author: archimag
> тоже самое нужно делать, например, если last-forms nil,
> то нужно его в список завернуть. вопрос в том, как этого не делать.

Я не понимаю проблемы. В коде макроса может выполняться произвольный код.
· original author: tmp.login
>Я не понимаю проблемы.
В том, что если нужно добавить к уже написанному коду (как в первом посте), список, который должен быть разделён, то нужно что-то менять в существующем. Получается, что вместо склевания всего в лист, а потом разрезания, сразу идёт разрезание. Вряд ли проблема серьёзная, но что-то типа values-list, но только в макрорасширение возвращается не список, а несколько значений,  примерно так:
(fn a b c (splice-it '(d e)) f) -> (fn a b c d e f)
Насколько я понимаю, то в CL этого сделать нельзя (без оборачивая конструкции в макрос ес-но).
· original author: tmp.login
>Получается, что вместо склевания всего в лист, а потом разрезания, сразу идёт разрезание.
в случае со splice-it.