2010-06-05 12 views
8

Me he estado mojando las manos con el ceceo de emacs, y una cosa que me sobresalta a veces es el alcance dinámico. ¿Hay mucho futuro para eso? La mayoría de los idiomas que conozco usan el alcance estático (o se han movido al ámbito estático, como Python), y probablemente porque lo sé mejor tiendo a preferirlo. ¿Hay aplicaciones/instancias específicas o ejemplos donde el alcance dinámico es más útil?utiliza para el alcance dinámico?

+2

Montones de [respuestas útiles aquí] (http://stackoverflow.com/questions/321000/dynamic-scoping-why) - ¿quizás esto es lo suficientemente cerca como para ser un duplicado? –

+0

Sí, parece que sí. Mi error. – hatmatrix

Respuesta

14

Hay una buena discusión sobre este problema here. La parte más útil que pertenece a su pregunta es:

Los enlaces dinámicos son excelentes para al modificar el comportamiento de los subsistemas. Supongamos que está utilizando una función 'foo' que genera salida usando 'imprimir'. Pero a veces le gustaría capturar la salida en un búfer de su elección . Con enlace dinámico, es fácil:

(let ((b (generate-new-buffer-name " *string-output*")))) 
    (let ((standard-output b)) 
     (foo)) 
    (set-buffer b) 
    ;; do stuff with the output of foo 
    (kill-buffer b)) 

(Y si se ha utilizado este tipo de cosas mucho , que le encapsular en una macro - pero por suerte ya se ha hecho tan 'con-salida-a-temp-buffer'.)

Esto funciona porque 'foo' utiliza el enlace dinámico del nombre 'standard-output', por lo que puede sustituir su propio unión para t sombrero nombre para modificar el comportamiento de 'foo' - y de todas las funciones que 'foo' llama.

En un lenguaje sin enlace dinámico, lo que probablemente agrega un argumento opcional a ‘foo’ para especificar un buffer y luego ‘foo’ que pasaría a cualquier llamadas a ‘imprimir’. Pero si 'foo' llama al otras funciones que a su vez llaman a 'print', también deberá modificar esas funciones . Y si 'imprimir' tenía otra opción, digamos 'nivel de impresión', , tendría que agregar eso también como argumento opcional ... Alternativamente, usted podría recordar el antiguo valor de 'salida estándar', sustituya su nuevo valor , llame a 'foo' y luego restaure el valor antiguo . Y recuerde manejar salidas no locales usando 'throw'. Cuando ha terminado con esto, verá que ha implementado el enlace dinámico !

Dicho esto, la vinculación léxica es en mi humilde opinión mucho mejor para el 99% de los casos. Tenga en cuenta que los Lisps modernos no son vinculantes dinámicos, solo como el ceceo de Emacs.

  • Common Lisp es compatible con ambas formas de vinculación, aunque el léxico se utiliza mucho más
  • especificación El Esquema ni siquiera se especifique vinculante (sólo un léxico) dinámico, aunque muchas implementaciones soportan ambos.

Además, los idiomas modernos como Python y Ruby que fueron un poco inspirado en Lisp por lo general apoyan léxica vinculante de una manera directa, con enlace dinámico también disponible pero menos sencillo.

7

Si lees el Emacs paper (escrito en 1981), hay una sección específica "Language Features for Extensibility" que trata esta cuestión. En Emacs, también existe el alcance agregado de las variables de buffer-local (archivo local).

he citado debajo de la parte más relevante:

Formal Parameters Cannot Replace Dynamic Scope

Algunos diseñadores del lenguaje creen que unión dinámica se debe evitar, y paso de argumentos explícito, deben utilizarse en lugar . Imagine que la función A vincula la variable FOO y llama a la función B , que llama a la función C, y C usa el valor de FOO. Supuestamente A debe pasar el valor como un argumento a B, que debe pasar como un argumento a C.

Esto no se puede hacer en un sistema extensible , sin embargo, porque el autor de el sistema no puede saber cuáles serán todos los parámetros . Imagine que las funciones A y C son parte de una extensión de usuario , mientras que B es parte del sistema estándar . La variable FOO does no existe en el sistema estándar; es es parte de la extensión. Para utilizar paso de argumentos explícitos habría requerir la adición de un nuevo argumento a B, lo que significa volver a escribir B y todo que llama B. En el caso más común, B es el orden del editor despachador bucle, que se llama a partir de una terrible cantidad de lugares.

Lo que es peor, C también se debe pasar un argumento adicional . B no refiere a C por nombre (C no existía cuando se escribió B ). Probablemente encuentre un puntero en C en la tabla de envío de comando . Esto significa que la misma llamada que a veces llama a C podría igualmente llamar a cualquier comando de editor definición. Por lo tanto, todos los comandos de edición deben reescribirse para aceptar e ignorar el argumento adicional. ¡Por ahora, ninguno del sistema original es dejado!

+0

Excelente cita! Este es realmente un excelente ejemplo de cómo la vinculación dinámica es útil. ¡Gracias por compartir! –

+0

Gracias, muy ilustrativo – hatmatrix

Cuestiones relacionadas