Elisp使用在函数列表中使用progn

问题描述 投票:2回答:3

我是emacs的新用户。并尝试编写一些Elisp以便更好地学习该软件。当我遇到一些问题时。

我想使用apply上的progn依次运行功能列表。但是我得到如下错误。我只是感到困惑,需要一些帮助来告诉我如何在Elisp中实现这一目标,谢谢。

(progn
  (+ 1 1)
  (+ 2 2)
  )
;; => 4

(apply #'progn ((+ 1 1) (+ 2 2)))
;; => Invalid function: (+ 1 1)

(apply #'progn ('(+ 1 1) '(+ 2 2)))
;; => Invalid function: '(+ 1 1)

(apply #'progn '((+ 1 1) (+ 2 2)))
;; => Invalid function: #<subr progn>

我像上面那样玩耍,因为我来自vim。所以我安装了邪恶号和邪恶号。并希望返回vim号inc和dec绑定C-a,C-x。所以我写了一个宏来避免模板化。

(defmacro set-evil-number-keymap (key-set func &rest modes)
  `(apply 'progn
         ,(-map
          (lambda (mode)
            `(define-key ,(intern (concat "evil-" mode "-state-map")) (kbd ,key-set)
              ',(intern
                 (concat "evil-numbers/" func))))
          ,modes)))

(set-evil-number-keymap "C-a" "inc-at-pt" "normal" "insert")
(set-evil-number-keymap "C-x" "dec-at-pt" "normal" "insert")

我的期望在下面。虽然它没有运行。


(progn 
(define-key evil-normal-state-map (kbd "C-a") ’evil-numbers/inc-at-pt) (define-key evil-visual-state-map (kbd "C-a") ’evil-numbers/inc-at-pt))

(progn 
(define-key evil-normal-state-map (kbd "C-x") ’evil-numbers/dec-at-pt) (define-key evil-visual-state-map (kbd "C-x") ’evil-numbers/dec-at-pt))


emacs apply elisp elisp-macro
3个回答
2
投票

您不能在具有特殊评估规则的apply之类的“特殊形式”上调用progn(请参阅信息(特殊)特殊形式)。

progn本身已经提供了一种用于顺序评估的机制,因此您的初次尝试确实可以完成您想要的事情。但是,在顶层,无论如何表单都将顺序执行,因此那里不需要progn


2
投票

您无需在宏中使用apply,否则elisp可以使用,@将列表平整为args。所以正确的答案是

(defmacro set-evil-number-keymap (key-set func &rest modes)
  `(progn
          ,@(-map
             (lambda (mode)
               `(define-key ,(intern (concat "evil-" mode "-state-map")) (kbd ,key-set)
                  ',(intern
                     (concat "evil-numbers/" func))))
             ,modes)))

0
投票

不确定您的期望。 progn返回最后一个格式的值,所以除4外,请参考C-h f progn

progn是`C源代码'中的一种特殊形式。

(progn身体...)

Eval BODY按顺序形成并返回最后一个的值。

例如,如果要查看(+ 1 1)的结果,则需要询问它,

(list (+ 1 1) (+ 2 2))
;; => (2 4)

;; Step 1
(list 2 (+ 2 2))

;; Step 2
(list 2 4)

;; Step 3
(2 4)

函数参数从左到右求值。顺便说一句,Emacs Lisp不支持多重返回值。


(apply #'progn ((+ 1 1) (+ 2 2)))
;; => Invalid function: (+ 1 1)

由于函数apply的第二个参数是((+ 1 1) (+ 2 2)),因此Emacs需要计算其值并计算像(foo 1 2 3)一样的格式,因此foo必须是一个函数,但是(+ 1 2)不是一个函数,这只是一个包含3个元素的普通列表。

(apply #'progn ('(+ 1 1) '(+ 2 2)))
;; => Invalid function: '(+ 1 1)

['(+ 1 2),也就是说,(quote (+ 1 2))也不是函数,它是包含两个元素的列表。

(apply #'progn '((+ 1 1) (+ 2 2)))
;; => Invalid function: #<subr progn>

progn不是函数,它是一种特殊形式。 andorletwhile都是特殊形式,它们就像宏一样,它们不急切地求参数。(elisp) Calling Functions提及

特殊形式和宏在'apply'中没有意义。

© www.soinside.com 2019 - 2024. All rights reserved.