2009-07-28 17 views
33

No sé si lo llamaría la formulación canónica, pero se unen a una función local me ha informado por el manual de GNU utilizar 'flet':dejó y flet en Emacs Lisp

(defun adder-with-flet (x) 
    (flet ((f (x) (+ x 3))) 
    (f x)) 
) 

Sin embargo , por accidente intenté (después de haber jugado en Scheme por un tiempo) la siguiente expresión, donde ato una expresión lambda a una variable usando 'let', y también funciona si paso la función a mapcar *:

(defun adder-with-let (x) 
    (let ((f (lambda (x) (+ x 3)))) 
    (car (mapcar* f (list x)))) 
) 

Y ambas funciones funcionan:

(adder-with-flet 3) ==> 6 
(adder-with-let 3) ==> 6 

¿Por qué funciona el segundo? No puedo encontrar ninguna documentación donde 'let' se pueda usar para vincular funciones a símbolos.

+0

Para cualquiera que trate de esto, tenga en cuenta que 'flet' podría no estar disponible en la versión de emacs que está utilizando, en cuyo caso probar un' (require 'cl) 'de antemano como se menciona a continuación (' flet' es una cosita de CommonLisp). – Robert

+0

¿Qué manual de GNU recomienda el uso de 'flet' aquí? – Stefan

+1

De Emacs 25.1.1 Describir Función: flet Esta macro está obsoleta desde 24.3; use cualquiera 'cl-flet 'o' cl-letf' – AAAfarmclub

Respuesta

37

A diferencia de Scheme, Emacs Lisp es un 2-lisp, lo que significa que cada símbolo tiene dos enlaces separados: el enlace de valor y el enlace de función. En una llamada de función (a b c d), se busca el primer símbolo (a) utilizando un enlace de función, el resto (b c d) se busca utilizando el enlace de valor. El formulario especial let crea un nuevo enlace de valor (local), flet crea un nuevo enlace de función.

Tenga en cuenta que si el valor o función se utiliza para la búsqueda de la unión depende de la posición en la llamada (a b c d) función, no en el tipo del Valor actualización. En particular, un enlace de valor puede resolverse para funcionar.

En el primer ejemplo, la función de las unen f (a través de flet), y luego hacer una función de búsqueda:

(f ...) 

En el segundo ejemplo, que el valor se unen f a una función (a través de let) , y luego usar un valor de búsqueda:

(... f ...) 

Tanto trabajo porque se utiliza el mismo tipo de vinculación y la consulta en cada caso.

http://en.wikipedia.org/wiki/Common_Lisp#Comparison_with_other_Lisps

+0

¡Gracias por la explicación! Veo, es una distinción entre value-lookup y function-searchup. Estaba familiarizado con la convención de tener espacios de nombres separados para las funciones y las variables, pero no pude conectar eso con cómo una función enlazada como una variable podría ser llamada por mapcar *. – hatmatrix

18

Hice una búsqueda rápida de las Emacs Lisp manual y no hemos encontrado ninguna referencia a 'flet, que no es muy sorprendente, ya que es una parte de cl - la common-lisp package.

let hará un enlace local también, pero no se vinculará con el "function cell" para ese símbolo.

decir que esto funciona:

(let ((myf (lambda (x) (list x x)))) 
    (eval (list myf 3))) 

pero

(let ((myf (lambda (x) (list x x)))) 
    (myf 3)) 

falla con el error: "Error de Lisp: (-función void myf)"

flet por el contrario, hace hacer el enlace a la celda de función, por lo que esto funciona:

(flet ((myf (x) (list x x))) 
    (myf 3)) 

Observe que la diferencia es que flet le permite usar el símbolo myf directamente, mientras que el let no lo hace; tiene que usar un direccionamiento indirecto para sacar la función de la "celda de valor" y aplicarla apropiadamente.

En su ejemplo, el 'mapcar' hizo el equivalente a mi uso de 'eval.

+0

¡Gracias por su respuesta! Junto con la explicación de zielaj, veo cómo esta cosa 'eval' también funciona. Sí, flet parece estar en la extensión cl; Originalmente había leído que (requiere 'cl) era necesario antes de usar flet pero supongo que en los emacs más nuevos esto ya no es el caso ... – hatmatrix

+5

Antes de que se enviara la extensión 'cl' con Emacs de fábrica, ¿cómo era posible? manejar las definiciones de funciones que necesitaban ser declaradas con semántica similar a let? ¿Simplemente se aceptó que eval es la forma de hacerlo? – d11wtq

7

@ d11wq hay `funcall' para este propósito. Las siguientes obras:

(defun adder-with-let (x) 
    (let ((f #'(lambda (x) (+ x 3)))) 
    (funcall f 3))) 

(adder-with-let 3) ;=> 6 
0

Usted no tiene que utilizar flet si no quiere. Se coloca una función en la célula de la función de un símbolo local definida usando let como en el siguiente ejemplo:

(let ((ALocalSymbol)) 
    (fset 'ALocalSymbol (lambda (x) (* 2 x))) 
    (ALocalSymbol 4) 
) 

Evaluar esta volverá 8. observe la cita frente a ALocalSymbol en (let ((ALocalSymbol))...). Mientras que setq cita símbolos, fset no.

flet es una especie de azúcar sintáctica. El uso de un let simple como antiguo para definir símbolos con valores nulos le permite elegir qué "celda" de un símbolo establecer. Puede usar setq para establecer la celda del valor del símbolo o fset para establecer la celda de la función.

Espero que esto ayude,

Pablo

+0

Esto es completamente incorrecto, y vincula la celda de función global (única) para el símbolo interno 'ALocalSymbol'. (Solo las celdas * value * están permitidas). Podrías hacer esto si estuvieras creando un símbolo * new * (no enterrado), en lugar de simplemente dejar-atar (el valor de) el símbolo interno. – phils

+0

Para mayor claridad: Este código define una función 'ALocalSymbol' en el espacio de nombres de la función global. Si una función con ese nombre ya se definió, se destruye. – phils

+0

Tenga en cuenta también que si creó un símbolo no intercalado, '(ALocalSymbol 4)' seguiría llamando a la función del símbolo interno, por lo que necesitaría 'funcall' (o similar) su símbolo/función no compartida. – phils

Cuestiones relacionadas