Что такое "нисходящие лучи"?
Джейми Завински использует этот термин в своей статье (1997) статье "java отстой" , как будто вы должны знать, что это значит:
Я действительно ненавижу отсутствие нисходящих лугов; анонимные классы - хромовая замена. (Я могу жить без долгоживущих закрытий, но я нахожу отсутствие указателей функций огромной болью.)
Кажется, что это Lisper slang, и я нашел следующее краткое определение здесь, но почему-то я думаю, что до сих пор не получаю это:
Многие замыкания используются только в той степени, в какой они связаны; они известны как "нисходящие лучи" в выражении Lisp.
Если бы не Steve Yegge, я бы сейчас просто почувствовал себя глупо, но, похоже, было бы нормально спросить:
Джейми Завински - герой. Живая легенда. [...] Парень, который может использовать термин "downarg funargs", а затем глядеть на вас, просто осмеливаясь попросить его объяснить это, вы кретин.
- XEmacs мертв, долго жить XEmacs
Итак, есть ли здесь Lisper, который может скомпилировать это для программистов C-стиля, таких как я?
Ответы
Ответ 1
Ненормальные funargs - это локальные функции, которые не возвращаются или иным образом оставляют область объявления. Они могут передаваться только другим функциям из текущего объема.
Два примера. Это понижающий эффект:
function () {
var a = 42;
var f = function () { return a + 1; }
foo(f); // `foo` is a function declared somewhere else.
}
Пока это не так:
function () {
var a = 42;
var f = function () { return a + 1; }
return f;
}
Ответ 2
Чтобы лучше понять, откуда взялся этот термин, вам нужно знать некоторую историю.
Причина, по которой старый хакер Lisp может отличить нижние funargs от funargs в целом, состоит в том, что нисходящие funargs легко реализовать в традиционном Lisp, который не имеет лексических переменных, тогда как общий случай трудный.
Традиционно локальная переменная была реализована в интерпретаторе Lisp путем добавления привязки (имя символа переменной в сочетании с ее значением) в среду. Такая среда была проста реализовать с использованием списка ассоциаций. Каждая функция имела свою собственную среду и указатель на среду родительской функции. Ссылка на переменную была решена путем поиска в текущей среде, а если не найдена, то в родительской среде и т.д. Стек стеков до достижения глобальной среды.
В такой реализации локальные переменные теневые глобальные переменные с тем же именем. Например, в Emacs Lisp, print-length
- это глобальная переменная, которая задает максимальную длину списка для печати перед аббревиатурой. Связывая эту переменную вокруг вызова функции, вы можете изменить поведение операторов печати внутри этой функции:
(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 ...)
Вы можете видеть, что в такой реализации нисходящие funargs действительно легко реализовать, потому что переменные, находящиеся в среде функции при ее создании, по-прежнему будут находиться в среде функции при ее оценке.
Переменные, которые действуют так, называются специальными или динамическими переменными, и их можно создать в Common Lisp, используя special
.
Ответ 3
В общем Lisp:
(let ((a 3))
(mapcar (lambda (b) (+ a b))
(list 1 2 3 4)))
-> (4 5 6 7)
В приведенной выше форме лямбда-функция передается DOWNWARD. Когда вызывается функцией MAPCAR более высокого порядка (которая получает функцию и список значений в качестве аргументов, а затем применяет эту функцию к каждому элементу списка и возвращает список результатов), функция лямбда по-прежнему относится к переменной 'a' из выражения LET. Но все это происходит внутри выражения LET.
Сравните выше с этой версией:
(mapcar (let ((a 3))
(lambda (b) (+ a b)))
(list 1 2 3 4))
Здесь функция lambda возвращается из LET. UPWARD немного. Затем он переходит к MAPCAR. Когда MAPCAR вызывает лямбда-функцию, ее окружающая LET больше не выполняется, но функция должна ссылаться на переменную 'a' из LET.
Ответ 4
Там есть довольно описательная статья о Wiki под названием проблема Funarg
"Нижняя луна может также ссылаться на состояние функции, когда эта функция фактически не выполняется. Однако, потому что, по определению, существование нижней гармоники содержится в выполнение функции, которая создает его, запись активации для функция обычно может быть хранится в стеке."