LINUX.ORG.RU

История изменений

Исправление quasimoto, (текущая версия) :

В реальности, как минимум в старых языках типа lisp - хрена лысого. Делают вид, что как бы появляется новая функция, но в реале никакой новой функции нету, только старые используются житрожопым образом.

Сделай let over lambda и будет тебе аллокация нового замыкания в куче с «кодогенерацией» (кавычки, так как это не значит, что обязательно будет дёргаться компилятор, можно аллоцировать новое на основе заранее сформированного машинного кода):

* (lambda (x) (+ x 1))

#<FUNCTION (LAMBDA (X)) {1002D942D9}>
* (defun get-closure (x) (let ((z x)) (lambda (y) (incf z y) z)))

GET-CLOSURE
* (defvar *first-closure* (get-closure 0))

*FIRST-CLOSURE*
* (defvar *second-closure* (get-closure 0))

*SECOND-CLOSURE*
* *first-closure*

#<CLOSURE (LAMBDA (Y)) {1002AE7AF9}>
* *second-closure*

#<CLOSURE (LAMBDA (Y)) {1002B48C29}>
* (funcall *first-closure* 1)

1
* (funcall *first-closure* 1)

2
* (funcall *first-closure* 1)

3
* (funcall *second-closure* 1)

1
* (funcall *second-closure* 1)

2
* (funcall *second-closure* 1)

3
* 

видим, что создаются два новых и разных (1002AE7AF9 и 1002B48C29) замыкания в куче (то есть собираемых GC). Для такого вот поведения они и должны быть разные и новые. В хаскеле, например, с иммутабельностью весь чистый код подвергается lambda liftingу и интенсивному inliningу, так что до рантайма не доживают ни лямбды (т.к. нет fixpoint оператора), ни замыкания (которых в чистом коде вообще нет) - только CAFs которые довольно легко статически компилировать. Реальные замыкания как в лиспе (= новые, каждый раз разные, в куче, собираемые GC) там возникнут только если их явно сделать через IO (с лямбдами с мутабельностью и IO lambda liftingу уже не справиться).

Ну я грешным делом подумал, что раз уж так прям про лямбду пишут, то наверно достигли того, что в учебнике написано - код генерят и всё такое. Оказалось - хрен там, одно унылое говно, да и то в качестве костыля.

Радоваться же надо, что код лишний раз в рантайме не генерируется (нет зависимости от компилятора, накладных расходов на тяжёлую генерацию и т.п.).

Исправление quasimoto, :

В реальности, как минимум в старых языках типа lisp - хрена лысого. Делают вид, что как бы появляется новая функция, но в реале никакой новой функции нету, только старые используются житрожопым образом.

Сделай let over lambda и будет тебе аллокация нового замыкания в куче с «кодогенерацией» (кавычки, так как это не значит, что обязательно будет дёргаться компилятор, можно аллоцировать новое на основе заранее сформированного машинного кода):

* (lambda (x) (+ x 1))

#<FUNCTION (LAMBDA (X)) {1002D942D9}>
* (defun get-closure (x) (let ((z x)) (lambda (y) (incf z y) z)))

GET-CLOSURE
* (defvar *first-closure* (get-closure 0))

*FIRST-CLOSURE*
* (defvar *second-closure* (get-closure 0))

*SECOND-CLOSURE*
* *first-closure*

#<CLOSURE (LAMBDA (Y)) {1002AE7AF9}>
* *second-closure*

#<CLOSURE (LAMBDA (Y)) {1002B48C29}>
* (funcall *first-closure* 1)

1
* (funcall *first-closure* 1)

2
* (funcall *first-closure* 1)

3
* (funcall *second-closure* 1)

1
* (funcall *second-closure* 1)

2
* (funcall *second-closure* 1)

3
* 

видим, что создаются два новых и разных (1002AE7AF9 и 1002B48C29) замыкания в куче (то есть собираемых GC). Для такого вот поведения они и должны быть разные и новые. В хаскеле, например, с иммутабельностью весь чистый код подвергается lambda liftingу и интенсивному inliningу, так что до рантайма не доживают ни лямбды (т.к. нет fixpoint оператора), ни замыкания (которых в чистом коде вообще нет) - только CAFs которые довольно легко статически компилировать. Реальные замыкания как в лиспе (= новые, каждый раз разные, в куче, собираемые GC) там возникнут только если их явно сделать через IO (с лямбдами с мутабельностью и IO lambda lifting уже не справиться).

Ну я грешным делом подумал, что раз уж так прям про лямбду пишут, то наверно достигли того, что в учебнике написано - код генерят и всё такое. Оказалось - хрен там, одно унылое говно, да и то в качестве костыля.

Радоваться же надо, что код лишний раз в рантайме не генерируется (нет зависимости от компилятора, накладных расходов на тяжёлую генерацию и т.п.).

Исходная версия quasimoto, :

В реальности, как минимум в старых языках типа lisp - хрена лысого. Делают вид, что как бы появляется новая функция, но в реале никакой новой функции нету, только старые используются житрожопым образом.

Сделай let over lambda и будет тебе аллокация нового замыкания в куче с «кодогенерацией» (кавычки, так как это не значит, что обязательно будет дёргаться компилятор, можно аллоцировать новое на основе заранее сформированного машинного кода):

* (lambda (x) (+ x 1))

#<FUNCTION (LAMBDA (X)) {1002D942D9}>
* (defun get-closure (x) (let ((z x)) (lambda (y) (incf z y) z)))

GET-CLOSURE
* (defvar *first-closure* (get-closure 0))

*FIRST-CLOSURE*
* (defvar *second-closure* (get-closure 0))

*SECOND-CLOSURE*
* *first-closure*

#<CLOSURE (LAMBDA (Y)) {1002AE7AF9}>
* *second-closure*

#<CLOSURE (LAMBDA (Y)) {1002B48C29}>
* (funcall *first-closure* 1)

1
* (funcall *first-closure* 1)

2
* (funcall *first-closure* 1)

3
* (funcall *second-closure* 1)

1
* (funcall *second-closure* 1)

2
* (funcall *second-closure* 1)

3
* 

видим, что создаются два новых и разных (1002AE7AF9 и 1002B48C29) замыкания в куче (то есть собираемых GC). Для такого вот поведения они и должны быть разные и новые. В хаскеле, например, с иммутабельностью весь чистый код подвергается lambda liftingу и интенсивному inliningу, так что до рантайма не доживают ни лямбды (т.к. нет fixpoint оператора), ни замыкания (которых в чистом коде вообще нет) - только CAFs которые довольно легко статически компилировать. Реальные замыкания как в лиспе (= новые, каждый раз разные, в куче, собираемые GC) там возникнут только если их явно сделать через IO (с лямбдами с мутабельностью lambda lifting уже не справиться).

Ну я грешным делом подумал, что раз уж так прям про лямбду пишут, то наверно достигли того, что в учебнике написано - код генерят и всё такое. Оказалось - хрен там, одно унылое говно, да и то в качестве костыля.

Радоваться же надо, что код лишний раз в рантайме не генерируется (нет зависимости от компилятора, накладных расходов на тяжёлую генерацию и т.п.).