2013-07-28 3 views
0

Я пытаюсь создать функцию в elisp, которая возвращает другую функцию. Я посмотрел на этот ответ на аналогичный вопрос (how to return function in elisp), но не понял ответа (я буквально сейчас начинаю изучать elisp сегодня, поэтому, пожалуйста, извините мое невежество). Я думал, что более простой пример поможет. Во-первых, рассмотрим функцию, проверить, является ли число делится на 5:Получение elisp для возврата функции в качестве возвращаемого значения

(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-идиоматический пример того, как можно реализовать этот шаблон, было бы полезно.

ответ

3

Во-первых, убедитесь, что вы включили lexical-binding. Самый простой способ сделать это - оценить (setq lexical-binding t) в текущем буфере. Более подробную информацию по теме можно найти here.

Ваше определение divisible-by-z в основном правильное, за исключением того, что у вас есть неправильный тип (обозначение обоих параметров z; параметр лямбда должен быть x). Кроме того, было бы более идиоматично вводить привязку для remainder с 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 

Конечно, вы также можете пропустить, указав его собственное имя enti полагаться и просто

(funcall (divisible-by-z 3) 10) ; => 0 

funcall необходимо потому, что Emacs Lisp является (в основном) Лисп-2, то есть он может присоединить как функцию и значение для данного символа. Поэтому, когда вы рассматриваете функции как значения (возвращающие одну из функции или передающую ее в функцию как параметр), вам, по сути, нужно сказать ей, чтобы она выглядела в этой ячейке, а не в обычной ячейке функции.Если вы ищете «Lisp-1 vs Lisp-2», вы найдете больше, чем хотите узнать об этом.

3

Возможное решение:

(defun divisible-by-3 (x) 
    (funcall (divisible-by-z 3) x))