2010-04-17 2 views
22

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

Я пытаюсь сделать это так, как я бы на схеме, но я получаю сообщение об ошибке: 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 ...))), но это не очень читаемый. Есть ли способ лучше?

ответ

27

Как и другие lisps (но не схема), Emacs Lisp имеет отдельные пространства имен для переменных и функций (т. Е. Это ‘Lisp2’, not a ‘Lisp1, см. Technical Issues of Separation in Function Cells and Value Cells о происхождении и значении этих терминов).

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

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

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

Внутренний механизм состоит в том, что каждый символ имеет номер multiple “cells”. Какая ячейка используется, зависит от where the symbol is in an evaluated form. Когда символ является первым элементом оцениваемой формы, its “function” cell is used. В любом другом положении, its “value” cell is used. В вашем коде do-work имеет функцию в своей ячейке значений. Для доступа к нему как функции вы используете funcall или apply. Если бы это было в функциональной ячейке, вы могли бы назвать это напрямую, используя свое имя в качестве автомобиля оцениваемой формы. Вы можете выполнить это с помощью flet or labels from the cl package.

21

ли (require 'cl) тянуть в Common 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)))) 
+2

+1. Мне действительно не нравятся Lisp-2s. – progo

4

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

(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.

Смежные вопросы