함수와 클로저: 행동과 기억

함수는 재사용 가능하도록 이름을 붙인 '행동'의 정의입니다. 클로저는 자신이 태어난 환경(맥락)을 기억하는 특별한 함수로, 코드에 생명력과 상태를 불어넣습니다.

리스펙스에서 함수는 로직과 추상화를 위한 기본 구성 요소입니다. 함수는 일급이므로 바인딩/전달/반환이 가능합니다.

함수 정의하기

이름 있는 함수는 define 설탕을, 익명 함수는 lambda를 사용합니다.

define으로 이름 있는 함수 정의하기

(define (add x y)
  (+ x y))

(add 5 10)     ; ⇒ 15

lambda로 익명 함수 정의하기

(lambda (n) (* n 2))

일급 시민으로서의 함수

"일급"이라는 것은 함수가 (숫자나 리스트와 같은) 다른 데이터 값처럼 취급된다는 것을 의미합니다. 함수는 다음과 같이 사용될 수 있습니다:

1. 바인딩에 저장하기

함수도 다른 값과 동일하게 바인딩할 수 있습니다.

(define square (lambda (n) (* n n)))
(define square-alias square)
(square-alias 10)                      ; ⇒ 100

2. 인자로 전달하기

함수를 다른 함수의 인자로 전달할 수 있습니다. 이는 고차 함수의 기본입니다.

(define (apply-it f v)
  (f v))

(define square (lambda (n) (* n n)))
(apply-it square 10)                   ; ⇒ 100

3. 다른 함수에서 반환하기

함수는 다른 함수를 생성하고 반환할 수 있습니다. 이 강력한 패턴은 아래 "클로저" 섹션에서 설명합니다.

클로저 이해하기

함수가 생성될 때, 그 함수가 정의된 환경(변수와 그 값들)을 포착(capture)합니다. 이 포착된 환경을 클로저라고 합니다. 이는 함수가 원래의 스코프(scope) 밖에서 호출될 때에도 값을 "기억"할 수 있게 해줍니다.

예시: 함수 팩토리

(define (make-adder amount-to-add)
  (lambda (n)
    (+ n amount-to-add)))

(define add-five (make-adder 5))
(define add-ten  (make-adder 10))

(add-five 100)   ; ⇒ 105
(add-ten 100)    ; ⇒ 110

재귀 (Recursion)

리스펙스에서 반복은 재귀를 통해 가장 자연스럽게(idiomatically) 달성됩니다. 이 접근 방식은 부수 효과(side effects)와 상태 변경(state mutations)을 피합니다.

(define (factorial n)
  (if (<= n 1)
      1
      (* n (factorial (- n 1)))))

(factorial 5)     ; ⇒ 120