gpt4 book ai didi

lisp - 如何在 Emacs Lisp 中动态更改 lambda 内容?

转载 作者:行者123 更新时间:2023-12-04 22:34:18 25 4
gpt4 key购买 nike

我有两个返回匿名函数的函数,除了几行之外几乎所有函数的内容都是一样的。

(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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com