2015-04-02 2 views
2

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

(defmacro my-defun (name lambda-list &body body &aux (fname (gensym))) 
    `(progn 
    (defun ,fname ,(all-vars lambda-list) 
     ,@body) 
    (defun ,name ,lambda-list 
     (,fname ,@(all-vars lambda-list))))) 

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

(defun all-vars (lambda-list) 
    (mapcar (lambda (cons) (if (consp cons) (car cons) cons)) 
      (remove-if (lambda (symbol) (and (symbolp symbol) 
              (char= (char (symbol-name symbol) 0) #\&))) 
        lambda-list))) 
+2

Вместо проверки первый символ является ли переменная # \ &, вы можете проверить, является ли символ в [** лямбда -list-ключевые слова **] (http://www.lispworks.com/documentation/HyperSpec/Body/v_lambda.htm). –

+0

Даже тогда вы должны следить за правильным синтаксисом и другими точными точками: 'lambda-list-keywords' имеет больше символов, чем те, которые разрешены в лямбда-списке функции, порядок имеет значение, аргументы' & optional' и '& key' могут быть минус, и они отличаются синтаксисом, '& aux' не являются действительно параметрами и т. д. – acelent

+0

@PauloMadeira Это абсолютно правильно, особенно о переменных & aux. Однако, поскольку расширение макроса включает в себя '(defun, name, lambda-list ...)', реализация уже должна проверять правильность списка лямбда, поэтому проверка не так важна в этом конкретном случае *. –

ответ

2

Этот подход является рода, что вы должны сделать, или нужно найти библиотеку, которая уже реализует его. Существуют библиотеки, которые обрабатывают анализ лямбда-списка (и каждая реализация должна делать это, по крайней мере, внутренне). Это обычно не слишком сложно, просто утомительно.

Тем не менее, ваша реализация all-vars не совсем верна. Полная спецификация ключевых аргументов в ordinary lambda lists является:

[&key {var | ({var | (keyword-name var)} [init-form [supplied-p-parameter]])}* [&allow-other-keys]] 

Это означает, что вы можете, например,

(defun (&key ((:long-keyword-name x) "EX" xp)) 
    ...) 

Когда вы (если (consp минусы) (автомобильные минусы) минусы), вы 'd get (: long-keyword-name x) назад, а не x.

Вот версия, которую я думаю работает, но не оттестирован:

(defun lambda-list-variables (lambda-list) 
    "Returns, in order, the variables declared in an ordinary lambda list, 
but doesn't check that the lambda-list is actually legal." 
    (labels ((ll-keyword-p (x) 
      (member x lambda-list-keywords)) 
      (to-var (x) 
      (if (symbolp x) 
       x    ; required, optional, rest, key, and aux 
       (destructuring-bind (var &rest init-and-supplied) x 
        (declare (ignore init-and-supplied)) 
        (if (listp var) 
         (second var)  ; key vars 
         var)))))   ; optional, key, and aux vars 
    (remove-if #'ll-keyword-p 
       (mapcar #'to-var lambda-list)))) 

CL-USER> (lambda-list-variables 
      '(a b 
      &optional c (d 'dee) (e 'ee e-p) 
      &rest f 
      &key 
      g 
      (h 'aitch) 
      (i 'eye i-p) 
      ((:jay j)) 
      ((:kay k) 'kay)    
      ((:ell l) 'ell l-p) 
      &aux 
      m 
      (n 'en))) 
;=> (A B C D E F G H I J K L M N) 
1

Так много раз я пишу функцию, как это только выяснить это уже в библиотеке александрии.

(ql:quickload :alexandria) 

А потом

CL-USER> (alexandria:parse-ordinary-lambda-list '(a b c &optional x &key (ham 1 used-ham))) 

возвращает

(A B C) 
((X NIL NIL)) 
NIL 
(((:HAM HAM) 1 USED-HAM)) 
NIL 
NIL 
T 
+0

не работает для метода лямбда-списков :(, но, возможно, я должен использовать александрию чаще всего. –

+0

@ cl-porky11: bummer. Извините, что я не тестировал его методами – Baggers

+0

уже написал (а) собственные функции для этого –

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