Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

레슨 04. 조립과 분해

CONS

cons는 리스트의 가장 기본적인 구성 요소입니다. 이는 함수므로 이의 인자들을 평가합니다. 리스트를 만들때에는 cons의 두번째 인자로 리스트 혹은 NIL이 들어올것입니다.

(cons 1 nil)
;;=> (1)

(cons 2 (cons 1 nil))
;;=> (2 1)

(cons 3 (cons 2 (cons 1 nil)))
;;=> (3 2 1)

cons는 새로운 항목을 리스트의 시작 부분에 추가합니다. 비어있는 리스트 ( ) 는 NIL과 동일하며,

( ) ==  NIL

따라서 이렇게 작성할 수 있습니다:

(cons 1 ())
;;=> (1)

(cons 2 (cons 1 ()))
;;=> (2 1)

(cons 3 (cons 2 (cons 1 ())))
;;=> (3 2 1)

혼란스럽게 느껴진다면, 맞습니다, NIL에는 뭔가 특별한 능력이 있습니다. NIL은 키워드는 아니지만 자기 자신을 상수 값으로 가지는 리스프의 두개의 심볼 중 하나입니다. 또 다른 심볼은 T입니다.

( ) == NIL이란 것과 NIL이 스스로 평가된다는 것을 종합해보면, 이는 (quote ())를 ()로 쓸 수 있다는 것을 의미합니다. 그렇지 않았다면, 리스프는 빈 리스트를 처리하기 위해 평가 규칙에 예외를 추가해야 했을 것입니다.

LIST

아마 여러분이 눈치챗다면, 중첩된 cons 폼으로도 리스트가 만들어질 수 있다는 것은 조금 지루할 수 도 있습니다. list 폼은 좀더 명료한 방법으로 동일한 일을 수행합니다:

(list 1 2 3)
;;=> (1 2 3)

list는 여러 인자를 취할 수 있습니다. list는 함수이기에, 이는 인자를 평가합니다:

(list 1 2 :hello "there" 3)
;;=> (1 2 :HELLO "there" 3)

(let ((a :this)
      (b :and)
      (c :that))
  (list a 1 b c 2))
;;=> (:THIS 1 :AND :THAT 2)

FIRST와 REST

리스트가 (첫번째와 나머지) 두 부분으로 만들어졌다고 가정한다면, 여러분은 first와 rest 두 연산자를 이용하여 리스트의 개별 원소들을 얻을 수 있습니다:

(setq my-list (quote (1 2 3 4 5)))
;;=> (1 2 3 4 5)

(first my-list)
;;=> 1

(rest my-list)
;;=> (2 3 4 5)

(first (rest my-list))
;;=> 2

(rest (rest my-list))
;;=> (3 4 5)

(first (rest (rest my-list)))
;;=> 3

(rest (rest (rest my-list)))
;;=> (4 5)

(first (rest (rest (rest my-list))))
;;=> 4

first와 rest 함수를 이리저리 엮는 것은 분명 지루한 작업일 것입니다. 또, 이러한 접근 법은 프로그램에서 특정 요소만을 선택하고자 할때나 혹은 리스트의 길이가 무한일때 잘 먹히지 않을 것입니다. 4장[p 84] 에서 재귀 함수를 정의할때 이러한 문제를 어떻게 해결하는지 살펴볼 것입니다. 나중에 13장에서 [p 150], 리스프가 제공하는 리스트 혹은 시퀀스 속 요소를 선택할 수 있는 함수들을 살펴 볼 것입니다

first와 rest는 꽤 최근 동안 활약해온 car와 cdr 함수의 이름을 바꾸어 리스프에 추가된 것입니다. 초기 리스프 구현체 중 하나에서 car와 cdr의 이름이 유례됬고, 이 이름에 기반한 구현체가 이미 오래전에 바뀌었음에도 불구하고 수십년간 고수되었습니다

짚고 넘어가기

  • cons
  • list
  • first
  • rest
  • car
  • cdr
  • nil , ( )
  • T