How can I write a mapping (e.g. a mapcar expression) to build the list for a use-package :hook clause?

I'm attempting to build the list in this :hook expression:

(use-package eglot
  :hook (
         (lorem-mode . eglot-ensure)
         (ipsum-mode . eglot-ensure)
         (dolor-mode . eglot-ensure)

by replacing the literal list with a mapcar expression:

(use-package eglot
   (lambda (lang-mode)
     (cons lang-mode '(. eglot-ensure)))

When I try evaluating the mapcar expression, it returns the list as expected.

((lorem-mode . eglot-ensure) (ipsum-mode . eglot-ensure) (dolor-mode . eglot-ensure))

When I try evaluating the entire use-package expression, it throws a Lisp error:

(wrong-type-argument listp lambda) […]

(If it's useful to show the entire traceback here I can; though hopefully the mistake I've made is obvious without that?)

How can I map (using mapcar or something more appropriate) a literal list of only the mode names, to generate the list-of-lists needed in :hook?


1 Answer 1


Look at the error message: (wrong-type-argument listp lambda). This means that it wanted a list, and it found a compiled lambda function. The reason for this is that use-package is a macro, and macros do not evaluate their arguments. This means that you cannot run any code here; you can only supply a literal list.

If you want to reduce the amount of typing that you need to do, you could write it like this instead:

(use-package eglot
  :hook ((lorem-mode ipsum-mode dolor-mode) . eglot-ensure))

For more information, see chapter 4.3 Hooks of the use-package manual.

  • "use-package is a macro, and macros do not evaluate their arguments". Thank you, that clearly explains the difference in behaviour.
    – bignose
    Commented Oct 3, 2023 at 0:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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