리스펙스에서 함수는 로직과 추상화를 위한 기본 구성 요소입니다. 함수는 일급이므로 바인딩/전달/반환이 가능합니다.
함수 정의하기
이름 있는 함수는 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