Я вижу два способа реализации привязок let
. Во-первых, как известно из SICP, let
может быть реализовано как лямбда-функция. Это удобно и просто, но с учетом того факта, что каждый лямбда (fn
) переведен в отдельный класс в JVM, и количество раз let
используется в средней программе, это кажется очень и очень дорогостоящим.Как `let` внедряется в Clojure и каковы его накладные расходы?
Второе, let
привязки могут быть переведены непосредственно в локальные переменные Java. Это дает очень небольшие накладные расходы, но сохранение привязок в стеке нарушает семантику языка: в этом случае создание закрытий просто невозможно - сохраненные значения будут уничтожены сразу после разворачивания стека.
Итак, какова фактическая реализация, используемая в Clojure? Оценивается ссылка на соответствующие строки в источнике Clojure.
Итак, я понимаю, что объект закрытия создан (и конечные переменные копируются на него) только тогда, когда это необходимо, и для простых случаев vars остаются в стеке? – ffriend
Да, это в значительной степени, как это работает. Если вас это интересует, вы можете зарыться в: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java (хотя не совсем понятно выяснить, что такое Clojure's компилятор делает, есть много «магии») – mikera
@ffriend Java имеет переменные с областью действия (в отличие от области метода). Я не смотрел, что делает компилятор Clojure, но кажется, что * let * может быть просто реализован блоком кода, содержащим конечные переменные. Я не уверен, почему вы думаете, что это будет реализовано с закрытием. –