использует для динамического объема? - PullRequest
8 голосов
/ 05 июня 2010

Я промочил руки от emacs lisp, и одна вещь, которая иногда сбивает меня с толку, это динамический прицел. Много ли у него будущего? Большинство языков, которые я знаю, используют статическую область видимости (или перешли на статическую область видимости, как Python), и, вероятно, потому что я знаю это лучше, я предпочитаю это делать. Существуют ли конкретные приложения / экземпляры или примеры, в которых динамическая область более полезна?

Ответы [ 2 ]

14 голосов
/ 05 июня 2010

Хорошее обсуждение этого вопроса здесь . Самая полезная часть, которая относится к вашему вопросу:

Динамические привязки отлично подходят для изменение поведения подсистем. Предположим, вы используете функцию «foo» который генерирует вывод, используя «print». Но иногда вы хотели бы захватить вывод в буфер вашего Выбор. С динамическим связыванием это легко:

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

(И если бы вы использовали такие вещи, много, вы бы заключили это в макрос - но к счастью это уже было сделано как 'С-выход-на-ТЕМП-буфера.)

Это работает, потому что "foo" использует динамическая привязка имени «Стандартный вывод», так что вы можете замените свою собственную привязку для этого имя, чтобы изменить поведение "foo" - и из всех функций, которые "foo" вызовов.

На языке без динамического связывания, вы, вероятно, добавили бы аргумент 'foo' для указания буфера и тогда «фу» передаст это любому звонки на «печать». Но если "Фу" звонит другие функции, которые сами называют «Распечатать», вам придется изменить эти функции также. И если «печать» имел другой вариант, скажем, «уровень печати», Вы должны добавить это в качестве дополнительного аргумент, а ... В качестве альтернативы, вы мог вспомнить старую ценность «Стандартный вывод», замените свой новый значение, вызовите «foo», а затем восстановите старое значение И не забудьте справиться нелокальные выходы с использованием «throw». когда вы покончили с этим, вы увидите что вы внедрили динамический связывание!

Тем не менее, лексическое связывание ИМХО намного лучше в 99% случаев. Обратите внимание, что современные Lisps не только для динамического связывания, как Emacs lisp.

  • Common Lisp поддерживает обе формы привязки, хотя лексическая используется гораздо чаще
  • Спецификация Scheme даже не определяет динамическое связывание (только лексическое), хотя многие реализации поддерживают оба.

Кроме того, современные языки, такие как Python и Ruby, которые были в некоторой степени вдохновлены Lisp, обычно поддерживают лексическое связывание прямым способом, с динамическим связыванием, также доступным, но менее простым.

7 голосов
/ 06 июня 2010

Если вы читаете статью Emacs (написанную в 1981 году), есть специальный раздел "Возможности языка для расширения" , в котором рассматривается этот вопрос. В Emacs также добавлена ​​область локальных буферных (файловых) переменных.

Я процитировал наиболее значимую часть ниже:

Формальные параметры не могут быть заменены Динамическая область действия

Некоторые дизайнеры языка считают, что следует избегать динамического связывания, и явная передача аргументов должна быть используется вместо Представьте себе, что функция А связывает переменную FOO и вызывает функция B, которая вызывает функцию C, а C использует значение FOO. Предположительно, А должен передать значение как аргумент B, который должен передать его в качестве аргумента С.

Это нельзя сделать в расширяемом Система, однако, потому что автор система не может знать, что все параметры будут. Представь, что функции A и C являются частью пользователя расширение, в то время как B является частью стандартная система. Переменная FOO делает не существует в стандартной системе; Это является частью расширения. Использовать явная передача аргументов будет требует добавления нового аргумента в B, что означает переписывание B и все что вызывает B. В наиболее распространенном случае, B - диспетчер команд редактора цикл, который вызывается из ужасного количество мест.

Что еще хуже, C также должен быть передан дополнительный аргумент. Б не относится к С по имени (С не существовало, когда Б было написано). Это, вероятно, находит указатель на C в командной рассылке Таблица. Это означает, что тот же вызов который иногда вызывает C мог бы одинаково хорошо вызвать любую команду редактора определение. Так что все редактирование Команды должны быть переписаны, чтобы принять и игнорировать дополнительный аргумент. От Теперь ни одна из оригинальной системы осталось!

...