Чтобы лучше понять, откуда появился этот термин, вам нужно знать историю.
Причина, по которой старый хакер Lisp может отличать фунгиры нисходящие от funargs в целом, заключается в том, что нисходящие funargs легко реализовать в традиционном Lisp, в котором отсутствуют лексические переменные, тогда как общий случай сложен. *
Традиционно локальная переменная была реализована в интерпретаторе Lisp путем добавления привязки (имя символа переменной в паре со ее значением) в среду . Такое окружение было просто реализовать с помощью списка ассоциаций. Каждая функция имела свое собственное окружение и указатель на окружение родительской функции. Ссылка на переменную была разрешена путем просмотра в текущей среде, а если ее там нет, то в родительской среде и т. Д. В стеке сред, пока не будет достигнута глобальная среда.
В такой реализации локальные переменные shadow глобальные переменные с одинаковыми именами. Например, в Emacs Lisp print-length
- это глобальная переменная, которая задает максимальную длину списка для печати до его сокращения. Связав эту переменную вокруг вызова функции, вы можете изменить поведение операторов print в этой функции:
(defun foo () (print '(1 2 3 4 5 6))) ; output depends on the value of print-length
(foo) ; use global value of print-length
==> (1 2 3 4 5 6)
(let ((print-length 3)) (foo)) ; bind print-length locally around the call to foo.
==> (1 2 3 ...)
Вы можете видеть, что в такой реализации downward funargs действительно легко реализовать, потому что переменные, которые находятся в среде функции, когда она создается, все еще будут в среде функции, когда она оценены.
Переменные, которые действуют так, называются специальными или динамическими переменными, и вы можете создать их в Common Lisp, используя объявление special
.