I have a bunch of add-to-list calls that I'd like to shorten in my .emacs file. They all look like this:

 (add-to-list 'align-rules-list
                (regexp . "\\(\\s-+\\)--\\s-+")
                (mode   . '(haskell-mode))
                (repeat . nil)))

I don't know lisp but I tried to define a local function that I can call repeatedly. I'm not getting very far:

(let ((f (lambda (name re)
           (list name
                 ('regexp . re)
                 '(mode . (haskell-mode))
                 '(repeat . nil))))))
 (funcall f 'haskell-comment "\\(\\s-+\\)--\\s-+"))

Can someone point out my problem with the code above?

After much googling, I've arrived at something that seems to work:

(let ((f (lambda (name re)
           (list name
                 (cons 'regexp re)
                 '(mode . '(haskell-mode))
                 '(repeat . nil))))))
 (funcall f 'haskell-comment "\\(\\s-+\\)--\\s-+")

But it seems messy. Quotes everywhere, cons, list. Is there a cleaner way?


defmacro is perfect for such use cases.

(defmacro my/add-to-align-rules-list-haskell (name re)
  `(add-to-list 'align-rules-list
                  (regexp . ,re)
                  (mode   . '(haskell-mode))
                  (repeat . nil))))
(my/add-to-align-rules-list-haskell haskell-comment "\\(\\s-+\\)--\\s-+")

How are you given the set of rule names and corresponding regexps? Assuming you have them in a list, just iterate over the list.

(defvar rule+regexp-alist '((haskell-comment . "\\(\\s-+\\)--\\s-+") (foo . "re1") (bar . "re2"))
  "(RULE . REGEXP) pairs, where RULE is a symbol and REGEXP is a string.")

(dolist (rl+re  rule+regexp-alist) 
  (add-to-list 'align-rules-list `(,(car rl+re)
                                   (regexp . ,(cdr rl+re))
                                   (mode 'haskell-mode)

(But are you sure it is 'haskell-mode you want in the result, instead of just haskell-mode? IOW, you want (mode 'haskell-mode) in the result, not just (mode haskell-mode)?)

(Yes, I ignored your request to "convert to a function", as I don't see the point of that, from your description. Sounds like you just want to make several similar calls to add-to-list. If so, then just do that - factor out the "similar" parts and iterate over the list of dissimilar parts.)


But it seems messy. Quotes everywhere, cons, list. Is there a cleaner way?

This should be what you're looking for.

  (regexp . ,re)
  (mode . (haskell-mode)) 
  (repeat . nil))

This is usually called the backquote, quasi-quote, or backtick.

Meanwhile, instead of let-binding f as a variable, you can use cl-flet which will let you use f as an actual function name. (Or you can just define a global function/macro, it's just a config file after all.) ;-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.