함수와 클로저

함수는 재사용할 수 있도록 이름을 붙인 행동의 정의입니다. 클로저는 자신이 태어난 환경을 기억하는 함수로, 상태 있는 로직을 만들 때 씁니다.

이전 문서입니다. 프로시저를 만들고 호출하려면 현재 매뉴얼의 프로시저 정의하고 호출하기를 읽으세요. 값을 기억하는 카운터를 만들려면 클로저와 카운터 상태를 보세요.

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

함수 정의하기

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

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

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

(add 5 10)     ; ⇒ 15

lambda로 익명 함수 정의하기

LISPEX
(lambda (n) (* n 2))

일급 시민으로서의 함수

"일급"이라는 것은 함수가 숫자나 리스트 같은 다른 값과 똑같이 취급된다는 뜻입니다. 함수는 다음과 같이 쓸 수 있습니다.

1. 바인딩에 저장하기

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

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

2. 인자로 전달하기

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

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

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

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

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

클로저 이해하기

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

예시: 함수 팩토리

LISPEX
(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)

리스펙스에서 반복은 재귀로 표현하는 것이 가장 자연스럽습니다. 이 접근 방식은 부수 효과와 상태 변경을 피합니다.

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

(factorial 5)     ; ⇒ 120