이 가이드는 리스펙스의 입력 표면에서 바인딩을 만드는 방법과 렉시컬 스코프가 어떻게 작동하는지 설명합니다. 실행 의미는 범위 밖이며 표준 양식만 사용합니다.
최상위 바인딩: define
최상위에서는 define으로 식별자에 값을 바인딩합니다.
(define x 10)
(define y (+ x 5)) ; y ⇒ 15
예약어는 바인딩할 수 없습니다.
스코프 이해하기
리스펙스는 렉시컬 스코핑을 사용합니다: 프로그램 구조로 스코프가 결정됩니다.
기본 규칙: 코드는 변수를 찾을 때 “바깥쪽”은 볼 수 있지만 “안쪽”은 볼 수 없습니다.
변수를 사용할 때, 인터프리터는 다음 순서로 변수를 검색합니다:
- 현재, 가장 안쪽의 스코프.
- 찾지 못하면, 부모 스코프(현재 스코프를 포함하는 스코프)를 확인합니다.
- ... 이런 식으로 전역 스코프까지 계속 올라갑니다.
(define global-val 100)
(let ((outer 3))
(let ((inner 4))
(+ global-val (* outer inner)))) ; ⇒ 112
;; 여기서는 `inner`를 볼 수 없습니다 (전역만 보임)
새로운 스코프 만들기
일반적으로 let 계열과 함수 호출로 중첩 스코프를 만듭니다.
1. let으로 지역 바인딩하기
(let ...)은 본문 안에서만 유효한 지역 바인딩을 만듭니다.
(define x 10)
(let ((x 20) (y 5))
(+ x y)) ; ⇒ 25
x ; ⇒ 10 (바깥 바인딩)
let*는 순차적으로 바인딩하고, letrec은 상호 재귀 지역 정의를 가능하게 합니다.
;; 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. 함수 호출
함수 호출은 파라미터와 지역을 위한 새 스코프를 만듭니다.
(define x 100)
(define (my-func param)
(let ((local 10))
(+ x param local)))
(my-func 50) ; ⇒ 160
기존 바인딩을 변경할 때는 set!을 사용합니다:
(define n 1)
(set! n (+ n 1)) ; n ⇒ 2
함수는 정의된 환경의 바인딩을 볼 수 있습니다(렉시컬 스코프). 자세한 내용은 함수와 클로저 문서를 참고하세요.