Подтвердить что ты не робот

Как создать временную функцию в Emacs Lisp

Я делаю некоторые утомительные звонки на кучу функций, но параметры будут определены во время выполнения. Я написал простую функцию, чтобы сохранить мой код DRY, но дать ему имя не нужно. Я не использую эту функцию где-либо еще.

Я пытаюсь сделать это так, как в Схеме, но получаю ошибку void-function:

(let ((do-work (lambda (x y z)
                  (do-x x)
                  (do-y y)
                  ;; etc
                  )))
  (cond (test-1 (do-work 'a 'b 'c))
        (test-2 (do-work 'i 'j 'k))))

Я мог бы вставить все это в apply (например, (apply (lambda ...) (cond ...))), но это не очень читаемо. Есть ли лучший способ?

4b9b3361

Ответ 1

Как и другие lisps (но не Scheme), Emacs Lisp имеет отдельные пространства имен для переменных и функций (т.е. это 'Lisp 2, а не 'Lisp 1, см. Технические вопросы разделения в функциональных ячейках и стоимости Ячейки для происхождения и значения этих терминов).

Вам нужно будет использовать funcall или apply для вызова лямбда (или другой функции), которая хранится в переменной.

(cond (test-1 (funcall do-work 'a 'b 'c))
      (test-2 (funcall do-work 'i 'j 'k))

Используйте funcall, если вы всегда будете отправлять одинаковое количество аргументов. Используйте apply, если вам нужно отправить переменное количество аргументов.

Внутренний механизм состоит в том, что каждый символ несколько "ячеек" . Какая ячейка используется, зависит от где символ находится в оценочной форме. Когда символ является первым элементом оцениваемой формы, используется его ячейка "function" . В любой другой позиции используется его ячейка "value" . В вашем коде do-work имеет функцию в своей ячейке значений. Чтобы получить доступ к ней как функции, вы используете funcall или apply. Если он находится в функциональной ячейке, вы можете вызвать его напрямую, используя его имя в качестве автомобиля оцениваемой формы. Вы можете выполнить это с помощью flet или labels из пакета cl.

Ответ 2

Сделайте (require 'cl), чтобы вытащить общий пакет Lisp, затем используйте flet вместо let:

(flet ((do-work (x y z)
          (do-x x)
          (do-y y)
          ;; etc
          ))
  (cond (test-1 (do-work 'a 'b 'c))
        (test-2 (do-work 'i 'j 'k))))

Ответ 3

Вы можете сделать это ANSI Common Lisp (хотя я думаю, что есть некоторые разработки Emacs, которые дадут вам неприятные взгляды):

(flet ((do-work (x y z)
                (do-x x)
                (do-y y)
                ;; etc
                ))
  (cond (test-1 (do-work 'a 'b 'c))
        (test-2 (do-work 'i 'j 'k))))

Не знаю, если вы сначала должны (require 'cl) (или cl-macs?) использовать flet. Если вы хотите определить рекурсивные функции, вам нужно использовать labels IIRC.