Lisp 宏展开的提问

以下代码

 ;;;use (define-key state (kbd "xxx") (kbd "yyy")) style map
 (macrolet ((keymap (state &rest groups)
                    (if (symbolp state)
                        (let ((res '(progn)))
                          (dolist (group groups)
                           (setq res (append res (list `(define-key ,(make-symbol (concatenate 'string "evil-" (symbol-name state) "-state-map"))
                                                                      (kbd ,(car group))
                                                                      (kbd ,(cadr group)))))))
                          res)
                        (let ((res '(progn)))
                              (dolist (a-state state)
                                (setq res (append res (list `(keymap ,a-state ,@groups)))))
                              res))))
   (keymap (normal visual) ("H" "8h")
                           ("L" "8l")
                           ("J" "5j")
                           ("K" "5k")))

我希望它展开成类似如下的代码

(progn
  (progn
    (define-key evil-normal-state-map (kbd "H") (kbd "8h"))
    (define-key evil-normal-state-map (kbd "L") (kbd "8l"))
    (define-key evil-normal-state-map (kbd "J") (kbd "8j"))
    (define-key evil-normal-state-map (kbd "K") (kbd "8k")))
  (progn
    (define-key evil-normal-state-map (kbd "H") (kbd "8h"))
    (define-key evil-normal-state-map (kbd "L") (kbd "8l"))
    (define-key evil-normal-state-map (kbd "J") (kbd "8j"))
    (define-key evil-normal-state-map (kbd "K") (kbd "8k"))))

但是在IELM中总是报错说 Symbol’s value as variable is void: evil-normal-state-map

猜想是

 `(define-key ,(make-symbol (concatenate 'string "evil-" (symbol-name state) "-state-map"))
                                                                   (kbd ,(car group))
                                                                   (kbd ,(cadr group)))

这段代码中,make-symbol的结果被当成全局变量了。

请问是这样吗?该如何解决呢?这个宏还有没有别的问题呢?

我看不懂,但我想问下为什么用 make-symbol 而不是 intern? :sweat_smile:

4 个赞
make-symbol is a built-in function in ‘C source code’.

(make-symbol NAME)

Return a newly allocated *uninterned* symbol whose name is NAME.
Its value is void, and its function definition and property list are nil.
(intern STRING &optional OBARRAY)

Return the canonical symbol whose name is STRING.

make-symbol 生成的符号不是全局可见的

(cl-macrolet ((keymap (state &rest groups)
                `(progn . ,(if (symbolp state)
                               (mapcar (lambda (group)
                                         `(define-key ,(intern (concat "evil-" (symbol-name state) "-state-map"))
                                                      (kbd ,(car group))
                                                      (kbd ,(cadr group))))
                                       groups)
                             (mapcar (lambda (a-state)
                                       `(keymap ,a-state . ,groups))
                                     state)))))
  (keymap (normal visual) ("H" "8h")
          ("L" "8l")
          ("J" "5j")
          ("K" "5k")))
1 个赞

(make-symbol (concatenate 'string "evil-" (symbol-name state) "-state-map"))

通常写 (intern (format "evil-%s-state-map" state))

因为写宏一定要避免改变当前context默认的obarray下具有和你声明的变量相同name的symbol的value,不然…

但他似乎就是要用那个全局变量啊

1 个赞

因为不知道有那个……

谢谢!明白了!