1

我正在尝试在 elisp 中创建一个返回另一个函数的函数。我查看了一个类似问题的答案(如何在 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 惯用示例也会有所帮助。

4

3 回答 3

4

首先,确保您已lexical-binding启用。(setq lexical-binding t)最简单的方法是在您当前的缓冲区中进行评估。可以在此处找到有关该主题的更多信息。

你的定义divisible-by-z基本上是正确的,除了你有一个错误类型(命名两个参数z;lambda的参数应该是x)。remainder此外,引入with的绑定会更惯用let-setq通常保留用于改变已经存在的绑定。结果如下:

(defun divisible-by-z (z)
  (lambda (x)
    (let ((remainder (% x z)))
      (if (= remainder 0) 1 0))))

你不能用你尝试过的方式defun来创建divisible-by-3——它期望新函数的参数列表是你调用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

funcall是必要的,因为 Emacs Lisp(基本上)是 Lisp-2,这意味着它可以将函数和值附加到给定符号。因此,当您将函数视为值(从函数返回一个或将一个作为参数传递给函数)时,您基本上必须告诉它查看该值“单元格”而不是通常的函数单元格。如果你搜索“Lisp-1 vs Lisp-2”,你会发现比你想知道的更多。

于 2013-07-29T23:53:44.570 回答
3

一个可能的解决方案:

(defun divisible-by-3 (x)
  (funcall (divisible-by-z 3) x))
于 2013-07-28T22:10:14.457 回答
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
于 2018-11-04T15:55:06.010 回答