- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有两个返回匿名函数的函数,除了几行之外几乎所有函数的内容都是一样的。
(defun foo ()
(interactive)
(lambda (arg)
(when (not (string-empty-p arg))
(message "foo")
(message arg))))
(defun bar ()
(interactive)
(lambda (arg)
(when (not (string-empty-p arg))
(message "bar")
(message arg))))
因此,我创建了一个接收列表作为参数并返回匿名函数的函数,如下所示:
(defun make-anonymous-func (&rest body)
(interactive)
(lambda (arg)
`(when (not (string-empty-p arg))
,@body
(message arg))))
但是,当我执行 make-anonymous-func
返回的函数时,lambda 中的列表被识别为列表文字并且没有被正确评估。
(funcall (make-anonymous-func '(message "foo")) "bar")
; ===> (when (not (string-empty-p arg)) (message "foo") (message arg))
有什么好的方法可以让它发挥作用吗?
谢谢。
最佳答案
像这样的形式
`(when (not (string-empty-p arg))
,@body
(message arg))
相当于这样的东西:
(append '(when (not (string-empty-p arg)))
body
((message arg))))
所以你的函数可以这样重写:
(defun make-anonymous-func (&rest body)
(lambda (arg)
(append '(when (not (string-empty-p arg)))
body
`((message arg)))))
我认为现在很清楚为什么这行不通了。更一般地说,反引号形式提供了一种简洁的方式来描述通过填充模板构建 s 表达式的方式,这在宏中很有用,因为 s 表达式表示 Lisp 源代码,而宏本质上是函数,其值是源代码,以及在您想要从模板构造 s 表达式的其他地方。
(做你想做的事情的一个可怕的方法是评估源代码的eval
。但是有很多原因导致这是一个非常糟糕的答案,所以我不会在这里深入讨论。)
做你想做的事情的一般方法是依赖词法范围。方便地 elisp 现在有词法作用域,所以你实际上可以这样做。以下两个示例假定 lexical-binding
为真。
首先,如果您只想捕获某些变量绑定(bind)的值,那么您可以这样做:
(defun make-anonymous-func (msg)
(lambda (arg)
(when (not (string-empty-p arg))
(message msg)
(message arg))))
第二种方法是,如果您希望该函数运行一些通用代码:这样做的方法是向它传递一个要调用的函数:
(defun make-anonymous-func (f)
(lambda (arg)
(when (not (string-empty-p arg))
(funcall f arg)
(message arg))))
现在
(funcall (make-anonymous-func
(lambda (m)
(message "foo")
(sit-for 1)))
"x")
将导致出现两条消息,但这次它们之间会有一个停顿,因此您会看到第一条。
最后一种可能性,如果您想做的是静态地创建一堆类似的函数——在编译时或定义时而不是在运行时动态地创建——是使用宏。
(defmacro define-messaging-function (name args &rest forms)
;; elisp has no destructuring, so check
(unless (and (listp args) (= (length args) 1)
(symbolp (car args)))
(error "bad arguments"))
(let ((arg (car args)))
`(defun ,name (,arg)
(when (not (string-empty-p ,arg))
,@forms
(message ,arg)))))
现在
(define-messaging-function foo (x)
(message "foo"))
将 foo
定义为一个函数,该函数在被调用时将执行原始 foo
函数返回的操作。
关于lisp - 如何在 Emacs Lisp 中动态更改 lambda 内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72768344/
我是一名优秀的程序员,十分优秀!