변수와 유효범위

리스펙스에서 바인딩을 만들고, 렉시컬 유효범위가 이름의 가시성을 정하는 방식을 설명합니다.

이전 문서입니다. 값에 이름을 붙이는 방법과 이름을 쓸 수 있는 범위는 바인딩, 스코프, 셀, 변경에서 확인하세요.

이 가이드는 리스펙스의 입력 표면에서 바인딩을 만드는 방법과 렉시컬 스코프가 어떻게 작동하는지 설명합니다. 표준 양식만 사용하며, 모든 예제는 플레이그라운드에서 바로 실행해 볼 수 있습니다.

최상위 바인딩: define

최상위에서는 define으로 식별자에 값을 바인딩합니다.

LISPEX
(define x 10)
(define y (+ x 5))      ; y ⇒ 15

예약어는 바인딩할 수 없습니다.

스코프 이해하기

리스펙스는 렉시컬 스코핑을 사용합니다. 스코프는 프로그램 구조가 결정합니다.

기본 규칙: 코드는 변수를 찾을 때 “바깥쪽”은 볼 수 있지만 “안쪽”은 볼 수 없습니다.

변수를 사용할 때 인터프리터는 다음 순서로 변수를 검색합니다.

  1. 현재, 가장 안쪽의 스코프.
  2. 찾지 못하면, 부모 스코프(현재 스코프를 포함하는 스코프)를 확인합니다.
  3. ... 이런 식으로 전역 스코프까지 계속 올라갑니다.
LISPEX
(define global-val 100)

(let ((outer 3))
  (let ((inner 4))
    (+ global-val (* outer inner))))      ; ⇒ 112
;; 여기서는 `inner`를 볼 수 없습니다 (전역만 보임)

새로운 스코프 만들기

일반적으로 let 계열과 함수 호출로 중첩 스코프를 만듭니다.

1. let으로 지역 바인딩하기

(let ...)은 본문 안에서만 유효한 지역 바인딩을 만듭니다.

LISPEX
(define x 10)

(let ((x 20) (y 5))
  (+ x y))                           ; ⇒ 25

x                                     ; ⇒ 10 (바깥 바인딩)

let*는 순차적으로 바인딩하고, letrec은 상호 재귀 지역 정의를 가능하게 합니다.

LISPEX
;; let* 순차 바인딩
(let* ((a 1)
       (b (+ a 2)))  ; a = 1을 볼 수 있음
  (+ a b))           ; ⇒ 4

;; letrec 지역 재귀
(letrec ((loop (lambda (xs acc)
                 (if (null? xs) acc
                     (loop (cdr xs) (+ acc (car xs)))))))
  (loop (list 1 2 3) 0))             ; ⇒ 6

2. 함수 호출

함수 호출은 파라미터와 지역을 위한 새 스코프를 만듭니다.

LISPEX
(define x 100)

(define (my-func param)
  (let ((local 10))
    (+ x param local)))

(my-func 50)                         ; ⇒ 160

기존 바인딩을 변경할 때는 set!을 사용합니다.

LISPEX
(define n 1)
(set! n (+ n 1))                      ; n ⇒ 2

함수는 정의된 환경의 바인딩을 볼 수 있습니다(렉시컬 스코프). 자세한 내용은 함수와 클로저 문서를 참고하세요.