让elisp返回一个函数作为返回值

时间:2013-07-28 22:06:13

标签: elisp

我正在尝试在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例子也会有所帮助。

3 个答案:

答案 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