2007년 12월 12일 수요일

Closure (클로저)

클로저란 함수나 코드 블록이 생성될 당시의 바인딩 정보를 같이 갖고 있는 것이라고 생각하면 된다. 다음 예를 보자.

(let ((counter 0))
(defun reset ()
(setf counter 0))
(defun stamp ()
(setf counter (+ counter 1))))

> (list (stamp) (stamp) (reset) (stamp))

(1 2 0 1)

지역변수 counter의 값이 0으로 설정된 상태에서 counter를 0으로 셋팅하는 함수 reset과 counter 값을 1 늘리는 stamp 함수를 선언하였다. stamp함수를 호출할 때마다 counter 값이 늘어나는 것을 볼 수 있다. 지역변수가 소멸하지 않고 바인딩이 계속 살아 있는 것이다. 하지만 counter는 지역 변수이기 때문에 외부에서 접근하거나 볼 수가 없다. 오로지 reset과 stamp를 통해서만 접근할 수 있는 것이다.

마치 가방 안에 어떤 물건을 넣고 가방을 닫으면(close over => closure) 가방을 열 때도 그 물건이 있는 것과 같이 함수나 코드 블록이 생성될 때 특정 지역변수에 대한 바인딩이 있으면 함수와 바인딩이 같이 살아있게 되는 것을 가리켜 클로저라고 하는 것 같다.

다른 예를 보자.

(defun make-adder (n)
#’(lambda (x)
(+ x n)))

> (setf add3 (make-adder 3))

#

> (funcall add3 2)

5

> (setf add27 (make-adder 27))

#

> (funcall add27 2)

29

make -adder는 n을 인자로 받아서 '어떤 인자를 받으면 n을 더해서 리턴하는 함수'를 리턴하는 함수다. (setf add3 (make-adder 3))은 3을 더해서 리턴하는 함수를 만들어서 add3이라는 변수에 저장한 것이다. add3과 add27을 보면 각각의 함수가 그 함수가 만들어질 때 파라미터로 주어진 n 값의 바인딩을 그대로 가지고 있는 것을 볼 수 있다.

댓글 없음: