我正在尝试在elisp中创建一个返回另一个函数的函数。我看了一个类似问题的答案(how to return function in elisp),但不明白答案(我实际上只是开始学习elisp,所以请原谅我的无知)。我认为一个更简单的例子会有所帮助。首先,考虑一个函数来测试一个数字是否可以被5整除:
(defun divisible-by-5 (x)
;; tests whether a number is divsible by 5.
(setq remainder (% x 5))
(if (= remainder 0) 1 0)
)
这很好用:
(divisible-by-5 25)
1
现在假设我想创建一个可以创建更多这类测试函数的函数,例如:
(defun divisible-by-z (z)
(lambda (z)
(setq remainder (% x z))
(if (= remainder 0) 1 0))
)
这不工作。例如,
(defun divisible-by-3 (divisible-by-z 3))
(divisible-by-3 4)
返回错误。我认为即使看到一个如何实现这种模式的elisp-idiomatic例子也会有所帮助。
答案 0 :(得分:3)
可能的解决方案:
(defun divisible-by-3 (x)
(funcall (divisible-by-z 3) x))
答案 1 :(得分:3)
首先,确保您已启用lexical-binding
。最简单的方法是评估当前缓冲区中的(setq lexical-binding t)
。有关该主题的更多信息可以在here找到。
你对divisible-by-z
的定义基本上是正确的,除了你有错误类型(命名两个参数z
; lambda的参数应该是x
)。此外,为remainder
引入let
的绑定更为惯用 - setq
通常保留用于突变已存在的绑定。结果如下:
(defun divisible-by-z (z)
(lambda (x)
(let ((remainder (% x z)))
(if (= remainder 0) 1 0))))
您无法使用defun
以您尝试过的方式创建divisible-by-3
- 它希望新函数的参数列表能够调用{{1} }。
您可以使用
创建全局动态绑定divisible-by-z
或与
的本地词汇绑定(defvar divisible-by-3 (divisible-by-z 3))
无论哪种方式,您都需要使用(let ((divisible-by-3 (divisible-by-z 3)))
...)
来调用函数
funcall
当然,您也可以完全轻松地给它自己的名字
(funcall divisible-by-3 9) ; => 1
(funcall (divisible-by-z 3) 10) ; => 0
是必要的,因为Emacs Lisp(基本上)是一个Lisp-2,这意味着它可以将函数和值附加到给定符号。因此,当您将函数视为值(从函数返回一个函数或将函数作为参数传递给函数)时,您必须告诉它查看该值“单元格”而不是通常的函数单元格。如果你搜索“Lisp-1 vs Lisp-2”,你会发现比你想知道的更多。
答案 2 :(得分:0)
另一种(也许更简单)的方法是将x
作为要传递给函数的变量:
(defun divisible-by-z (x z) "
Check if x is divisible by z.
If so, return 0.
If not, return the remainder."
(if (% x z) (% x z) 0))
因此:
(divisible-by-z 5 2) --> 1
(divisible-by-z 4 2) --> 0