클로저와 공유 변경 상태

클로저는 값을 복사해 얼려 두지 않고 어휘 셀을 캡처합니다. 그래서 관련된 프로시저들이 하나의 비공개 바인딩을 함께 쓸 수 있습니다.

실행으로 확인하기

LISPEX
(define counter (let ((n 0)) (lambda () (set! n (+ n 1)) n)))
(list (counter) (counter))

관측 결과

OUTPUT
(1 2)

패턴 따라가기

  1. 비공개 셀을 만듭니다. 바깥 letcounter를 만들 때 n을 한 번 할당합니다.
  2. 셀 대신 동작을 반환합니다. let이 끝난 뒤 그 바인딩에 닿을 수 있는 값은 람다뿐입니다.
  3. 공유 갱신을 관측합니다. 두 호출이 같은 클로저를 부르므로 두 번째 호출은 첫 호출이 실행한 set!의 결과를 봅니다.

이 순서로 생각하세요

  • 상태는 바깥 let에서 만듭니다. 그 상태를 읽거나 바꾸는 프로시저를 반환하고, 셀에는 그 프로시저를 거쳐서만 닿게 합니다.
  • 가려진 바인딩은 별개의 셀을 할당합니다. set!은 가장 가까운 해석 바인딩을 갱신합니다.
  • 최상위 재정의는 이전 클로저가 보는 원래 전역 셀을 갱신합니다.

직접 확인하기

바깥 let을 두 번 평가해 counter-acounter-b를 만들어 보세요. counter-a를 호출하면 counter-b도 바뀔까요?

아닙니다. 각 평가는 서로 다른 어휘 셀을 할당합니다. 클로저가 같은 셀을 캡처할 때만 상태를 공유합니다.

흔한 오해

여기서 공유 변경은 결정적입니다. 그래도 소유 범위는 좁게 잡고 명시적으로 테스트해야 합니다.

다음으로

정확한 셀·섀도잉 규칙은 바인딩에서 확인하세요. 상태를 명시적 입력으로 바꿀 수 있다면 결정 규칙 가이드가 더 단순한 길입니다.

바인딩과 스코프 · 결정 규칙