LINUX.ORG.RU

[lisp][замыкания] что-то важное упускаю

 


0

0

У финнов есть такой пример кода:

[code] _(setq y 10) 10 _(setq s (function (lambda (x) (+ x y)))) (LEXICAL_CLOSURE ...) _(funcall s 2) 12 _(setq y 100) 100 _(funcall s 2) 12 [/code]

Видно, что как и положено, значение свободной переменной Y сохраняется в замыкании.

Но это - в книжке. В clisp происходит так:

[code] [15]>(setq y 10) 10 [16]> (setq s (function (lambda (x) (+ x y)))) #<FUNCTION :LAMBDA (X) (+ X Y)> [17]> (funcall s 2) 12 [18]> (funcall s 2) 12 [19]> (setq y 100) 100 [20]> (funcall s 2) 102 [/code]

То есть "не работает".

Думаю, что я упустил какую-то важную деталь, связанную с работой самого clisp

anonymous

И еще

sbcl вообще ругается:

* (setq y 100)

; in: LAMBDA NIL
;     (SETQ Y 100)
;
; caught WARNING:
;   undefined variable: Y

;
; caught WARNING:
;   This variable is undefined:
;     Y
;
; compilation unit finished
;   caught 2 WARNING conditions

anonymous
()

форматирование...

У финнов есть такой пример кода: 
_(setq y 10)
10 
_(setq s (function (lambda (x) (+ x y))))
(LEXICAL_CLOSURE ...) 
_(funcall s 2) 
12 
_(setq y 100) 
100 
_(funcall s 2) 
12

Видно, что как и положено, значение свободной переменной Y сохраняется в замыкании. 

Но это - в книжке. В clisp происходит так: 
[15]>(setq y 10) 
10 
[16]> (setq s (function (lambda (x) (+ x y)))) 
#<FUNCTION :LAMBDA (X) (+ X Y)> 
[17]> (funcall s 2) 
12 
[18]> (funcall s 2) 
12 
[19]> (setq y 100) 
100 
[20]> (funcall s 2) 
102

То есть "не работает". 
Думаю, что я упустил какую-то важную деталь, связанную с работой самого clisp

anonymous
()
Ответ на: комментарий от anonymous

setq - разрушающее присваивание. Надо использовать defvar.

А книга финнов вообще не про Common Lisp.

anonymous
()
Ответ на: комментарий от anonymous

defvar создаст динамическую переменную.

anonymous
()

В этом примере для clisp y находится в одной области видимости для
setq и полученного замыкания, поэтому его изменение сказывается не
работе замыкания. Вот пример как сделать так, как у финнов (кстати,
что это за финны?):

(setq y 10) ; sbcl тут ругался потому что y не объявлена ранее.
            ; Правильнее было бы написать (defvar y 10), как уже 
            ; заметили выше
(let ((y y))
  (setq s (lambda (x) (+ x y))))

Так можно разделять переменные между несколькими функциями, например:

(let ((y 10))
  (setq s (lambda (x) (+ x y)))
        m (lambda (x) (* x y)))
        change-y (lambda (x) (setq y x))))
(funcall s 10) ; 20
(funcall m 10) ; 100
(funcall change-y 5)
(funcall s 10) ; 15
(funcall m 10) ; 50

Jini ★★
()

У тебя не получается замыкания, о чем тебе clisp как-бы напомнает (#<FUNCTION :LAMBDA...).

Это происходит из-за того, что y и s находятся в одном лексическом окружении. Про различные окружения CL достаточно продробно написано в HyperSpec.

Macil ★★★★★
()
Ответ на: комментарий от anonymous

>_(setq y 10)
>10

>_(setq s (function (lambda (x) (+ x y))))

Не знаю, кто такие финны, но тут лексическим замыканием и не пахнет.
'y' биндится в null-lexical-enviroment. Как бы просто глобальная переменная.
Лексическое замыкание - захват переменной из лексического окружения.
Примеры форм, создающих лексические биндинги - (defun ...) (lambda ...) и (let ...)
(defun foo (y)
(lambda (x) (setq y (+ x y))))

(defparameter fn (foo 5))

(funcall fn 6)
==> 11

(funcall fn 7)
==> 18

anonymous
()
Ответ на: комментарий от anonymous

Финны - авторы архивредной книги "Мир лиспа", весьма популярной в свое время из-за красивых картинок с деревцем.

anonymous
()
Ответ на: комментарий от Macil

>находятся в одном лексическом окружении.

Извини, я тебе безбожно наврал. defvar, defparameter объявляют динамические переменные (неявно declare-ят переменные как special). Поэтому и замыкания не получается.

У меня вот другой вопрос почему (let ((x 10)) (lambda () x)) не является замыканием? Это работает оптимизатор?

Macil ★★★★★
()
Ответ на: комментарий от dave

Да, та самая и вроде вообще единственная.

Macil ★★★★★
()
Ответ на: комментарий от Macil

>У меня вот другой вопрос почему (let ((x 10)) (lambda () x)) не является замыканием? Это работает оптимизатор?

Сам не знаю. Предполагал, что это особенности диалекта или же реализации. Буду чтиать про лексическое окружение.

Кстати, спасибо всем откликнувшимся.

anonymous
()
Ответ на: комментарий от Macil

>У меня вот другой вопрос почему (let ((x 10)) (lambda () x)) не является замыканием?
>Это работает оптимизатор?

Да, это фактически оптимизация компилятора.

anonymous
()
Ответ на: комментарий от Macil

>(let ((x 10)) (lambda () x)) не является замыканием?

кстати, работает

[10]> (let ((yy 10))
  (setq s (lambda (x) (+ x yy))))
#<FUNCTION :LAMBDA (X) (+ X YY)>
[11]> (funcall s 2)
12
[12]> (setq yy 100)
100
[13]> (funcall s 2)
12

вместо y сделал yy, т.к.  ранее было
(defvar y 10)
и действительно не работало

ps: а clisp вообще обязан про closure говорить? или он всегда про функции?

anonymous
()
Ответ на: комментарий от anonymous

он все функциями называет, если про печать в repl
интерпретируемая функция отображается как #<FUNCTION -имя- -аргументы- -тело-функции->
скомпилированная - #<COMPILED-FUNCTION -имя->

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