Лексические замыкания над макролетом? - PullRequest
5 голосов
/ 20 февраля 2010

Есть ли способ сделать что-то вроде лексического замыкания, используя macrolet? Что я хочу сделать, так это сделать следующий макрос локальным рекурсивным помощником, который вызывает функцию для каждой комбинации вместо генерации списка, как это теперь происходит, вызывая макрос в repl, что приводит к:

CL-USER> (combinations nil '(1 2 3) '(4 5 6))
((1 4) (1 5) (1 6) (2 4) (2 5) (2 6) (3 4) (3 5) (3 6))

То, что я хотел бы, это макрос, который принимает функцию и любое количество списков и приводит к появлению вложенных циклов, которые вызывают функцию для каждой комбинации. Я довольно новичок в lisp, это первый макрос, который я написал за пределами клонов 'nif' и т.п., поэтому любые предложения приветствуются.

Я пытался превратить макрос в макроклет в макросе, который принимает функцию, и строка '(nreverse (list, item, @ vars))' заменяется на '(func (nreverse (list, item, @vars))) 'но я получаю ошибки, утверждая, что func - неопределенная переменная или функция.

Это оригинальная функция:

(defmacro combinations (vars &rest lsts)
  (with-gensyms (item)
    `(loop for ,item in ,(car lsts) ,(if (null (cdr lsts)) 'collecting 'nconcing)
       ,(if (null (cdr lsts))
            `(nreverse (list ,item ,@vars))
            `(combinations (,item ,@vars) ,@(cdr lsts))))))

Это то, что я пробовал с макросом и получаю неопределенную ошибку функции 'func'.

(defmacro for-all-combonations (func &rest lst)
       (macrolet ((for-all (vars &rest lsts)
                    (with-gensyms (item)
                      `(loop for ,item in ,(car lsts) ,(if (null (cdr lsts)) 
                                                           'collecting 'nconcing)
                            ,(if (null (cdr lsts))
                                 `(func (nreverse (list ,item ,@vars)))
                                 `(for-all (,item ,@vars) ,@(cdr lsts)))))))
         (for-all nil lst)))

1 Ответ

5 голосов
/ 21 февраля 2010

Макросы не являются первоклассными объектами в Common Lisp, поэтому вы не можете иметь эквивалент лексического замыкания в качестве макроса. Вы можете получить аналогичный эффект, создав функцию, которая генерирует список, который является допустимой программой на Лиспе, а затем проверяет его.

Это, вероятно, не очень хорошее решение вашей проблемы. Как сказал Райнер Йосвиг, макросы предназначены для манипулирования исходным кодом. Используйте их, когда вам нужна новая синтаксическая форма, которая не встроена в язык. Не используйте их там, где вы можете написать то, что вы хотите, с помощью обычных функций.

...