10

This causes an error

(cl-destructuring-bind 
    (&key a b) 
    '(:a "foo" :b 13 :c "bar") 
  (list a b)) 

because the :c key/value is not handled in the pattern match.

Often I find myself wanting to extract some subset of keys/values from a plist, but cl-destructuring-bind isn't appropriate because of this limitation.

Is there a way to make cl-destructuring-bind simply ignore unmatched keys in the EXPR? I'm not sure what the official common lisp behaviour is supposed to be here, is the error in the spec?

Note that the dash library has some support for a similar destructuring with -let, but that requires some boilerplate to assign a symbol to each key. A fix has been proposed

Taking Stefan's answer into account, this works well:

(defmacro plist-bind (args expr &rest body)
  "`destructuring-bind' without the boilerplate for plists."
  `(cl-destructuring-bind
       (&key ,@args &allow-other-keys)
       ,expr
     ,@body))

(plist-bind
  (a b)
 '(:a "foo" :b 13 :c "bar")
 (list a b)) => ("foo" 13)
fommil
  • 1,750
  • 11
  • 24

2 Answers2

11

Since cl-destructuring-bind uses CommonLisp's arglist convention, you should be able to do:

(cl-destructuring-bind 
    (&key a b &allow-other-keys) 
    '(:a "foo" :b 13 :c "bar") 
  (list a b))
Stefan
  • 26,154
  • 3
  • 46
  • 84
  • 1
    Not merely “should be able to”. It actually does work. – Harald Hanche-Olsen May 26 '16 at 06:19
  • I wrote a macro to make it easier to use – fommil May 28 '16 at 15:46
  • I've been getting some strange non-reproducible errors with this macro, is `cl-destructuring-bind` known to have any problems? https://github.com/ensime/ensime-emacs/issues/458 – fommil Jun 01 '16 at 21:55
  • I don't think there are known problems in `cl-destructuring-bind` (well, there are some minor issues but none that should lead to incorrect behavior, AFAIK). OTOH I'm not sure how heavily it's been tested. – Stefan Jun 02 '16 at 01:22
2

see definition of cl-defmacro:

(VAR...                                                                                                                                                                                                              
    [&optional (VAR [INITFORM [SVAR]])...]                                                                                                                                                                              
    [&rest|&body VAR]                                                                                                                                                                                                   
    [&key (([KEYWORD] VAR) [INITFORM [SVAR]])... [&allow-other-keys]]                                                                                                                                                   
    [&aux (VAR [INITFORM])...]                                                                                                                                                                                          
    [&environment VAR]) 

All of which are allowed for cl-destructuring-bind besides &environment