트랙
/
Common Lisp
Common Lisp
/
연습 문제
/
Leslie의 긴 리스트
Leslie의 긴 리스트

Leslie의 긴 리스트

학습 연습 문제

소개

배열

우리가 사용하는 언어의 이름인 Lisp은 _LIST Processing_을 뜻하니까, 이 언어에 항목들의 배열을 다루는 기능이 있겠구나 하고 짐작할 수 있는데, 맞아요!

Common Lisp에는 배열 외에도 다른 자료 구조가 있지만, 배열은 여전히 아주 많이 쓰여요.

Common Lisp에서 배열은 항목들의 시퀀스예요. cons라고도 부르는데, 주로 역사적인 이유 때문이에요. 항목들은 꼭 같은 타입일 필요는 없어요. 예를 들어 1, two, "III"로 이루어진 배열을 만들 수 있어요.

배열 만들기

다음처럼 인용한 배열을 그냥 입력하면 돼요: '(1 two "III"). 그러면 배열이 만들어지고 평가돼요. 평과 결과는 (1 two "III")예요.

배열을 만드는 데 쓰이는 주요 함수도 두 가지 있어요: list와 cons.

list는 인자를 0개 이상 받아서, 그 값들로 만들어진 배열로 평가돼요:

(list 1 'two "III") ; => (1 two "III")

cons는 두 항목을 받아서, 첫 번째 항목을 car(배열의 머리)로, 두 번째 항목을 cdr(나머지 부분)로 하는 배열을 만들어요:

(cons 1 2)            ; => (1 . 2) ;; (a list without `nil` as its `cdr` is printed in this way)
(cons 1 nil)          ; => (1)
(cons 1 (cons 2 nil)) ; => (1 2)

car와 cdr 함수를 사용하면 배열의 car와 cdr에 접근할 수 있어요.

(first와 rest는 car와 cdr의 동의어이고, 완전히 똑같이 동작해요.)

길이와 임의 접근

배열의 길이는 length로 구할 수 있어요. 빈 배열의 길이는 0이에요.

임의의 항목에는 nth로 접근할 수 있어요(배열의 인덱스는 0부터 시작해요).

배열의 길이보다 큰 인덱스를 요청해도 오류가 아니에요. 대신 nil로 평가돼요:

(nth 23 '(short list)) ; => nil

배열의 앞쪽 항목들에 접근하는 데 쓰이는 여러 도우미 메서드도 있어요: first, second, third부터 tenth까지요. 멋지죠?

배열 합치기

두 개 이상의 배열은 append로 합칠 수 있어요:

(append '(a b c) '(1 2 3)) ; => (A B C 1 2 3)
(append '(a b c) '())     ; => (A B C)

append에 전달하는 인자는 각각 배열이어야 해요.

지침

Lisp 외계인 레슬리는 장을 좀 봐야 해요. 장을 볼 때는 장보기 배열을 만들어 두는 게 아주 중요하죠. 거기에 물건을 넣기도 하고, 빼기도 해야 하니까요.

물론 Lisp 외계인에게 종이와 펜만으로는 부족해요. "List"는 "Lisp"라는 단어의 대부분을 차지하기도 하니까요! 장보기를 관리할 수 있게 도와주는 함수가 분명히 필요하겠죠.

레슬리가 장보기 배열을 잘 관리할 수 있도록 도와줄래요?

1. 새 배열 만들기

먼저 레슬리는 빈 배열을 만들어야 해요. new-list라는 함수가 딱 맞겠죠.

(new-list) ; => ()

이런... 레슬리는 이미 생각해 둔 물건이 몇 개 있어서, 세 개의 항목을 받아 (다행히 레슬리는 세 개짜리 배열만 만들어요. 그보다 많지도 적지도 않아요!) 그것들로 새로운 장보기 배열을 만드는 함수가 필요해요. 세 개의 항목을 받아 그것들을 담은 배열을 반환하는 list-of-things 함수를 작성해 봐요.

(list-of-things 'bread 'milk 'butter) ; => '(bread milk butter)

2. 배열에 항목 추가하기

가게에 가기 전에 레슬리는 식료품 저장고를 살펴보며 무엇이 필요한지 확인해요. 배열의 맨 앞에 항목을 추가하는 add-to-list 함수를 작성해서 도와줘요.

(add-to-list 'butter '(bread)) ; => '(butter bread)

3. 배열에서 다음 항목은 뭘까요?

장을 볼 때 레슬리는 다음에 무엇을 찾아야 할지 알고 싶어 해요. 또 배열에서 두 번째, 세 번째, 심지어 스물세 번째 항목(레슬리의 행운의 숫자예요)까지 미리 훔쳐보는 걸 좋아하죠.

  • first-thing은 배열의 첫 번째 항목으로 평가돼요
  • second-thing은 두 번째 항목으로 평가돼요
  • third-thing은 세 번째 항목으로 평가돼요
  • twenty-third-thing은 스물세 번째 항목으로 평가돼요
(first-thing '(bread butter milk)) ; => 'bread
(second-thing '(bread butter milk)) ; => 'butter
(third-thing '(bread butter milk)) ; => 'milk

4. 배열에서 항목 하나 제거하기

레슬리는 배열의 첫 번째 항목을 찾아서 선반에서 치우고 싶어 해요. 입력받은 배열에서 첫 번째 항목만 빼고 나머지를 담은 배열로 평가되는 remove-first-item 함수를 작성해서 도와줘요.

(remove-first-item '(bread butter milk)) ; => '(butter milk)

5. 작은 배열로 더 큰 배열 만들기

레슬리는 실수로 장보기 배열을 하나가 아니라 두 개나 만들었다는 걸 깨달았어요! 첫 번째 배열의 원소들 뒤에 두 번째 배열의 원소들이 이어지는 배열을 반환하는 list-append 함수를 작성해 봐요.

(list-append '(bread salt) '(butter milk)) ; => '(bread salt butter milk)

6. 얼마나 길까요?

레슬리는 이번 장보기가 꽤 오래 걸릴까 봐 걱정되기 시작했어요. 대체 이 배열에는 물건이 몇 개나 들어 있을까요? 배열의 길이를 알려 주는 just-how-long 함수를 작성해 봐요.

(just-how-long '(bread milk butter salt)) ; => 4
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Common Lisp Exercism

Leslie의 긴 리스트 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Common Lisp 트랙을 개념 27개연습 문제 92개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.