0

I am trying to avoid duplicating code and also trying to avoid introducing unnecessary global symbols. So I tried to use let, dolist and lambda when defining the same keys in two different keymaps:

(let ((key (kbd "S-<down>"))
      (def (lambda ()
             (interactive)
             (unless (evil-visual-state-p)
               (evil-visual-state))
             (evil-next-line))))
  (dolist (map '(evil-normal-state-map evil-insert-state-map))
    (define-key map key def)))

Here I want S-down to have the same definition in both evil-normal-state-map and in evil-insert-state-map.

This gives me error:

Wrong type argument: keymapp, evil-normal-state-map
5
  • Think I found the error: I need to use symbol-value on the list variable map: (define-key (symbol-value map) key def). Still curious why I need to do that :) Oct 27, 2016 at 12:41
  • 1
    define-key requires the keymap itself and not some symbol but you iterate over the symbols with your dolist. eval would also do instead of symbol-value.
    – Tobias
    Oct 27, 2016 at 14:15
  • 3
    Or iterate over keymaps instead of symbols: (dolist (map (list evil-normal-state-map evil-insert-state-map))...
    – npostavs
    Oct 27, 2016 at 14:55
  • I find this curious--most functions take some value or a symbol with some value. Only accepting a value is inconvenient, to say the least. May 9, 2017 at 6:33
  • @tianxiang-xiong: I'm curious: could you give an example of such a function ?
    – duthen
    Sep 19, 2022 at 10:26

1 Answer 1

0

According to Chapter 2 : "Lisp Data Types", of the Emacs Lisp manual:

Each object belongs to one and only one primitive type. These types include integer, float, cons, symbol, string, vector, hash-table, subr, and byte-code function, plus several special types, such as buffer, that are related to editing.

and from Chapter 2.3.6 : "Cons Cell and List Types" :

A cons cell is an object that consists of two slots, called the CAR slot and the CDR slot. Each slot can hold any Lisp object. We also say that the CAR of this cons cell is whatever object its CAR slot currently holds, and likewise for the CDR. A list is a series of cons cells, linked together so that the CDR slot of each cons cell holds either the next cons cell or the empty list. The empty list is actually the symbol nil. Because cons cells are so central to Lisp, we also have a word for an object which is not a cons cell. These objects are called atoms.

And from Chapter 21.3 : "Format of Keymaps":

Each keymap is a list whose CAR is the symbol keymap. The remaining elements of the list define the key bindings of the keymap. A symbol whose function definition is a keymap is also a keymap. Use the function keymapp (see below) to test whether an object is a keymap.

When I quote an object, I get an object of type symbol, whereas a keymap is an object of primitive type cons, type list, and constructed type keymap.

The define-key function expects a first argument of type keymap. This is checked by define-key using the keymapp predicate function. If the argument is not of type keymap, it will throw an exception.

According to Chapter 8.1 : "Symbol Components" :

Each symbol has four components (or “cells”), each of which references another object:

Print name
The symbol’s name.

Value
The symbol’s current value as a variable.

Function
The symbol’s function definition. It can also hold a symbol, a keymap, or a keyboard macro.

Property list
The symbol’s property list.

The print name cell always holds a string, and cannot be changed. Each of the other three cells can be set to any Lisp object.

According to Chapter 9.5 : "Eval" :

Eval

Most often, forms are evaluated automatically, by virtue of their occurrence in a program being run. On rare occasions, you may need to write code that evaluates a form that is computed at run time, such as after reading a form from text being edited or getting one from a property list. On these occasions, use the eval function. Often eval is not needed and something else should be used instead. For example, to get the value of a variable, while eval works, symbol-value is preferable

When I do dolist on a quoted list of keymaps, I get a list of objects of type symbol, whereas each symbol's value slot has a keymap object. Hence, my problem can be solved by passing each symbol's value to define-key, instead of the symbol itself.

According to the comments by @Tobias and @npostavs, there are many ways to solve my problem. For example, we could solve this using either symbol-value, eval, or list. Hence, the following three examples will all pass an object of type keymap as first argument to lookup-key:

(dolist (kmap '(global-map))
  (message-box "%s" (lookup-key (symbol-value kmap) (kbd "C-h"))))
(dolist (kmap '(global-map))
  (message-box "%s" (lookup-key (eval kmap) (kbd "C-h"))))
(dolist (kmap (list global-map))
  (message-box "%s" (lookup-key kmap (kbd "C-h"))))
1
  • The last option, the one that passes dolist a list of keymaps instead of a list of symbols, is much, much better than the others. It expresses intent more directly: "for each keymap, add this binding" vs "for each of these names of keymaps, lookup which keymap is named by it and add this binding".
    – Omar
    Nov 5, 2016 at 2:33

Your Answer

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

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