2016-04-14 1 views
0

У меня есть функция, как этогоКак использовать & key и & rest в cl-defun togather?

(cl-defun foo (a b c d e &rest f) 
    nil) 

Аргументы c, d и e являются nil 80% времени.

Чтобы сделать это выглядит лучше, я делаю это:

(cl-defun foo (a b &rest f &key c d e &allow-other-keys) 
    nil) 

Когда c, d и e не предусмотрено, это нормально.

Однако, если один из них используется, f получает неправильный аргумент. Например:

(foo 1 2 :c 6 3 4 5) 
;; ==> expected: a=1, b=2, c=6, f= (3 4 5) 
;; ==> real case: a=1, b=2, c=6, f= (:c 6 3 4 5) 

ответ

0

поведения вы видите, один указанный CommonLisp (на самом деле я не уверен, если ваш звонок (foo 1 2 :c 6 3 4 5) даже действует в CommonLisp, потому что я думаю, что это будет относиться к 3 и 5 вырожденным ключевые слова и ключевое слово 5 не имеет значения).

IOW список, который вы получаете через &rest включает все ключевые слова. Поэтому, если вы не хотите их, вы должны бросить их вручную (в этот момент вам часто лучше не использовать &key).

0
(cl-defmacro foo2 (a b &rest f &key c d e &allow-other-keys) 
    (let (key rest) 
    (dolist (elt f) 
     (if (memq elt '(:c :d :e)) 
      (setq key elt) 
     (if key 
      (progn 
       (set (intern-soft (string-remove-prefix ":" (symbol-name key))) elt) 
       (setq key nil)) 
      (push elt rest)))) 
    (setq rest (nreverse rest)) 

    `(foo ,a ,b ,c ,d ,e ,@rest))) 

(pp-macroexpand-expression '(foo2 1 2 :c 3 :d 4 :e 5 6 7 8 9)) 
;; ==> (foo 1 2 3 4 5 6 7 8 9) 
(pp-macroexpand-expression '(foo2 1 2 3 4 5 6)) 
;; ==> (foo 1 2 nil nil nil 3 4 5 6) 
(pp-macroexpand-expression '(foo2 1 2 3 4 5 6 :c 7 :d 8 :e 9)) 
;; ==> (foo 1 2 7 8 9 3 4 5 6) 
(pp-macroexpand-expression '(foo2 1 2 3 :c 4 5 :d 6 7 :e 8 9)) 
;; Extreme case 
;; ==> (foo 1 2 4 6 8 3 5 7 9) 

С предложением Штефана я придумал это. Я не очень хорош в макросе, это работает?

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