값, 이름, 프로시저

리스펙스가 리터럴과 호출을 읽는 방법을 익히고, `define`과 `let`으로 이름을 붙이고, `lambda`로 재사용할 프로시저를 만듭니다.

1단계에서는 완전한 프로그램을 실행했습니다. 이번에는 그 안에 들어 있던 몇 가지 모양을 하나씩 떼어 봅니다. 값이 있고, 값을 가리키는 이름이 있고, 값을 계산하는 프로시저 호출이 있습니다. 이 셋을 구분하면 괄호는 일정한 순서로 읽힙니다.

값은 홀로 설 수 있습니다

수, 불리언, 문자열, 문자, 인용 데이터는 값입니다.

LISPEX
42
#t
"Lispex"
#\L
'ready

작은따옴표가 없는 ready는 다릅니다. 리스펙스는 이것을 이름으로 보고 값을 찾습니다. 'ready라고 쓰면 심볼이 데이터로 남습니다.

호출 위치의 리스트는 일을 요청합니다

아래 식을 가장 안쪽부터 읽어 봅시다.

LISPEX
(+ 10 (* 2 3))

리스펙스는 먼저 +를 찾습니다. 그다음 10을 평가하고, (* 2 3)을 왼쪽부터 차례로 평가합니다. 안쪽 호출의 결과가 6이므로 바깥 호출은 (+ 10 6)을 계산하는 것과 같습니다.

결과

OUTPUT
16

괄호가 모두 평범한 호출은 아닙니다. define, lambda, let, if는 어느 부분을 평가할지, 이름이 어디에서 보일지를 정합니다.

값에 이름 붙이기

define은 최상위 바인딩을 만들거나 갱신합니다.

LISPEX
(define fee 3)
(+ 20 fee)

결과

OUTPUT
23

정의는 아무것도 출력하지 않습니다. 마지막 덧셈만 값 하나를 출력합니다.

이름이 본문 한 곳에서만 필요하면 let을 씁니다.

LISPEX
(let ((base 7))
  (* base 2))

결과

OUTPUT
14

base라는 이름은 본문 안에서만 보입니다. 임시 계산의 범위를 좁게 잡으면 규칙을 점검하기 쉽습니다.

다시 쓰는 프로시저 만들기

프로시저를 정의하는 축약 형식에서는 프로시저 이름과 입력 이름을 나란히 적습니다.

LISPEX
(define (price-with-fee price fee)
  (+ price fee))

(price-with-fee 20 3)

결과

OUTPUT
23

긴 형식으로 쓰면 프로시저도 값이라는 점이 더 잘 드러납니다.

LISPEX
(define price-with-fee
  (lambda (price fee)
    (+ price fee)))

프로시저는 인자 개수를 검사합니다. price-with-fee에 인자를 하나만 주거나 세 개를 주면 기본값을 임의로 채우지 않고 런타임 오류를 냅니다.

조각을 합치기

LISPEX
(define (price-with-fee price fee)
  (+ price fee))

(list (price-with-fee 20 3)
      (let ((base 7))
        (* base 2)))

결과

OUTPUT
(23 14)

리스트의 첫 번째 원소를 계산한 다음 두 번째 원소를 계산합니다. list는 이렇게 준비된 두 값을 받아 (23 14)를 만듭니다.

연습

입력에 3을 곱하는 triple을 정의하세요. 그런 다음 list 안에서 두 번 호출해 (12 21)을 반환하세요.

답 하나 보기
LISPEX
(define (triple n)
  (* n 3))

(list (triple 4) (triple 7))

3단계로 갈 준비가 됐나요?

인용한 심볼이 왜 데이터인지, (* 2 3)이 왜 바깥 덧셈보다 먼저 끝나는지, let으로 만든 이름이 어디에서 보이는지 설명할 수 있으면 다음으로 넘어가도 좋습니다. 다음은 데이터, 조건, 결정입니다.