LINUX.ORG.RU

Вопрос по компиляции

 


0

2

Часто, когда объясняется ФП, при рассмотрении локального скопа можно встретить, как бы, объяснение процесса, что, якобы ф-ция «ищет» значения свободных переменных в локальном скопе, когда вызывается. На самом деле, ничего ведь в рантайме не ищется, все подстановки уже произведены в компилтайме. Например:

(let ((a 1)) (lambda(b) (+ a b)))
Тут после стадии компиляции будет всего лишь
(lambda(b)(+ 1 b))
а если b не меняется, то компилятор вообще сразу вычислит результат. Таким образом, никакого лексического скопа вообще не существует фактически. В первом примере, мы могли бы безо всяких замыканий написать вместо a 1, от этого ни хрена не изменится, правильно?


Ответ на: комментарий от quasimoto

http://www.scs.stanford.edu/11au-cs240h/notes/ghc-slides.html

http://www.scs.stanford.edu/11au-cs240h/notes/memory-slides.html

(http://www.scs.stanford.edu/11au-cs240h/notes/, http://www.scs.stanford.edu/14sp-cs240h/slides/)

^ В heap profiler-е FUN_* вполне можно иногда увидеть, то есть они динамически генерируются (хотя и тонкой прослойкой, благодаря оптимизациям).

Пример (let ((a 1)) (lambda (b) (+ a b))) как ((lambda (a) (lambda (b) (+ a b))) 1) редуцируется до (lambda (b) (+ 1 b)), так что не пример — нужно чтобы нельзя было редуцировать по месту определения (то что можно редуцировать по месту использования не интересно — в общем случае они не известны).

Типичный пример:

(+)
\x -> (+x)
\x y -> x + y
\x -> \y -> x + y

(не масло масляное, а просто в языке с частичными применениями всё потенциально замыкание)

(defun adder (a) (lambda (b) (+ a b)))
(SBCL не знае как это не сделать замыканием :))
auto adder(int x) { return [=](int y) { return x + y; }; }
(adderi: movl %edi, %eax; ret — знают, допустим, если std::function не использовать)

или

map (*) -- :: [Int] -> [Int -> Int]
map (\x -> (*x))
map (\x y -> x * y)
map (\x -> \y -> x * y)
\xs -> map (\x -> \y -> x * y) xs

(есть код (*), map (*) возвращает из списка чисел список функций умножающих на эти числа — наверно это будет список замыканий в общем случае)

(defun mm (xs)
  (mapcar (lambda (x) (lambda (y) (* x y))) xs))
(тем более (#<CLOSURE ...> ...))
auto mm(std::vector<int> const& xs) {
    std::vector<std::function<int(int)>> rs;
    for (auto const x : xs) rs.push_back([=](int y) { return x * y; });
    return rs;
}
(over 500LOC в .s)

quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 2)
Ответ на: комментарий от KblCb

Я смотрю, тема понравилась :) Ну, хорошо, «на усмотрение компилятора». Уболтали.

dave ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.