2010-04-17 20 views
22

Sto facendo alcune noiose chiamate a un sacco di funzioni, ma i parametri saranno determinati in fase di esecuzione. Ho scritto una semplice funzione per mantenere il mio codice ASCIUTTO ma dargli un nome non è necessario. Non uso questa funzione da nessun'altra parte.Come creare una funzione temporanea in Emacs Lisp

sto cercando di farlo nel modo in cui avrei nello Schema, ma ottengo un errore di 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)))) 

ho potuto attaccare il tutto in un apply (ad esempio, (apply (lambda ...) (cond ...))), ma che non è molto leggibile C'è un modo migliore?

risposta

27

Come altri lisps (ma non Scheme), Emacs Lisp dispone di spazi dei nomi separati per variabili e funzioni (ad esempio, è un ‘Lisp2’, not a ‘Lisp1; vedere Technical Issues of Separation in Function Cells and Value Cells per l'origine e il significato di questi termini).

È necessario utilizzare funcall o apply per chiamare un lambda (o un'altra funzione) che è memorizzato in una variabile.

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

Usa funcall se sarà sempre inviare lo stesso numero di argomenti. Utilizzare apply se è necessario essere in grado di inviare un numero variabile di argomenti.

Il meccanismo interno è che ogni simbolo ha multiple “cells”. Quale cella viene utilizzata dipende da where the symbol is in an evaluated form. Quando un simbolo è il primo elemento di un modulo valutato, its “function” cell is used. In qualsiasi altra posizione, its “value” cell is used. Nel codice, do-work ha la funzione nella sua cella del valore. Per accedervi come una funzione, utilizzare funcall o apply. Se si trovava nella cella della funzione, è possibile chiamarlo direttamente utilizzando il suo nome come auto di un modulo valutato. È possibile eseguire questa operazione con flet or labels from the cl package.

21

fare (require 'cl) a tirare nel pacchetto Common Lisp, quindi utilizzare flet invece di 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. Non mi piacciono davvero i Lisp-2. – progo

4

Si può fare questo il modo ANSI Common Lisp (anche se penso che ci sono alcuni devels Emacs che vi darà brutto aspetto):

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

so se per prima cosa dovete (require 'cl) (o cl-macs) da utilizzare flet. Se si desidera definire funzioni ricorsive, è necessario utilizzare labels IIRC.

Problemi correlati