2016-04-14 21 views
0

Ich habe eine Funktion wie dieseWie benutzt man & key und & rest in einem cl-defun togather?

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

Argumente c, d und enil 80% der Zeit ist.

Um es sieht besser aus, ich dies tun:

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

Wenn c, d und e nicht vorgesehen sind, ist es in Ordnung.

Wenn jedoch einer von ihnen verwendet wird, erhält f ein falsches Argument. Zum Beispiel:

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

Antwort

0

Das Verhalten, das Sie sehen, ist die von CommonLisp angegeben (mir nicht sicher bin, ob tatsächlich Ihr Anruf (foo 1 2 :c 6 3 4 5) auch gültig in CommonLisp ist, weil ich denke, es 3 und 5 als entartet behandeln würde Schlüsselwörter und das 5 Schlüsselwort fehlt ein Wert).

IOW die Liste erhalten Sie über &rest enthält alle Schlüsselwörter. Also, wenn Sie sie nicht wollen, müssen Sie sie von Hand fallen lassen (an diesem Punkt sind Sie oft besser nicht &key überhaupt verwenden).

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) 

Mit @ Stefans Vorschlag komme ich auf diese Idee. Ich bin nicht wirklich gut im Makro, funktioniert es?