하스켈에서 리스트는 동질(homogenous)의 데이터 구조이다. 리스트는 같은 타입의 원소를 가진다. 이 말은 정수의 리스트 또는 문자 리스트 등은 가질 수 있지만, 정수 일부, 문자 일부로 구성되는 리스트는 존재하지 않는다는 의미이다.
* let 키워드를 이용하여 GHCI 에서 이름을 정의할 수 있다. GHCI 에서 let a = 1 이라고 하는 것은 스크립트에 a = 1 이라고 쓰고 로딩하는 것과 동일하다.
- Prelude> let lostNumbers = [4,8,15,16,23,42]
- Prelude> lostNumbers
- [4,8,15,16,23,42]
- Prelude>
리스트는 대괄호로 표현되고고, 리스트의 값들은 콤마로 구분되어진다.
문자에 관해서 이야기하면 문자열은 단지 문자의 리스트라고 보면 된다. 즉, "hello" 는 ['h','e','l','l','o'] 의 리스트인 셈이다. 문자열이 리스트인 관계로, 그에 대해서도 간단하게 리스트 함수를 응용할 수 있다. ++ 연산자를 이용해서 2개의 리스트를 결합하는 것이 가장 기본적인 예이다.
- Prelude> [1,2,3,4] ++ [9,10,11,12]
- [1,2,3,4,9,10,11,12]
- Prelude> "hello" ++ " " ++ "world"
- "hello world"
- Prelude> ['w','o'] ++ ['o','t']
- "woot"
++ 연산자를 통해 리스트를 결합할 때 내부적으로 하스켈은 ++ 왼쪽의 리스트 전체를 순회한다. 리스트가 크지 않을 때는 문제가 되지 않지만, 규모가 클 때는 상당히 시간이 걸릴 수 밖에 없다. 이에 반해 : 연산자(이른바 cons operator)의 경우 결과처리는 즉각적이다. 다음의 예를 보자.
- Prelude> 'A':" SMALL CAT"
- "A SMALL CAT"
- Prelude> 5:[1,2,3,4,5]
- [5,1,2,3,4,5]
[1,2,3] 는 사실 1:2:3:[] 의 syntactic sugar 일 뿐이다. [] 는 비어있는 리스트이다. 여기에 3을 덧붙이면 [3]이 된다. 거기에 2를 덧붙이면 [2,3] 이 된다. 이런 식이다.
그리고 아래 셋은 서로 다른 것이다.
[] - 비어있는 리스트
[[]] - 비어있는 리스트를 포함하고 있는 리스트
[[],[],[]] - 3개의 비어있는 리스트를 포함하고 있는 리스트
인덱스를 이용하여 리스트내의 원소를 가져올 때는 !! 을 사용한다. 인덱스는 0 에서 시작한다. 하지만 6번째 원소를 가져오려고 하면, 에러가 발생한다.
- Prelude> "Steve Buscemi" !! 6
- 'B'
- Prelude> [9.4,33.2,96.2,11.2,23.25] !! 1
- 33.2
- Prelude> [9.4,33.2,96.2,11.2,23.25] !! 6
- Prelude>
리스트 역시 리스트를 포함할 수 있다. 그리고 리스트를 포함한 리스트를 포함한 리스트도 가능하다.
- Prelude> let b = [[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
- Prelude> b
- [[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
- Prelude> b ++ [[1,1,1,1]]
- [[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3],[1,1,1,1]]
- Prelude> [6,6,6]:b
- [[6,6,6],[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
- Prelude> b !! 2
- [1,2,2,3,4]
숫자와 문자가 섞인 리스트를 만들 수 없듯이, 문자로 이루어진 리스트와 숫자로 이루어진 리스트를 모두 포함하는 리스트는 만들 수 없다(즉, 서로 다른 타입의 리스트를 하나의 리스트에 포함할 수 없다).
포함된 원소들이 비교가능하다면 리스트 역시 비교가능하다. <, <=, > 그리고 >= 를 리스트를 비교할 때 사용할 때는 사전적 순서(lexicographical order)로 비교된다. 먼저 헤드가 비교되면, 그것이 동일하다면 그 다음 원소가 서로 비교되는 것이다.
- Prelude> [3,2,1] > [2,1,0]
- True
- Prelude> [3,2,1] > [2,10,100]
- True
- Prelude> [3,4,2] > [3,4]
- True
- Prelude> [3,4,2] > [2,4]
- True
- Prelude> [3,4,2] == [3,4,2]
- True
head 명령어는 리스트를 가져와 그 리스트의 헤드를 반환한다. 리스트의 헤드는 기본적으로 리스트의 첫번째 원소를 의미한다. tail은 헤드를 제외한 나머지를 반환한다. last 는 리스트의 가장 마지막 원소를 반환한다. 마지막으로 init는 마지막 원소를 제외한 나머지를 반환한다.
- 5
- [4,3,2,1]
- 1
- [5,4,3,2]
만약 빈 리스트에 헤드를 적용하면 어떻게 될까? 아래에서 보듯이 head, tail, last, init 명령은 빈 리스트에는 적용할 수 없다.
- Prelude>
'프로그래밍 Programming' 카테고리의 다른 글
하스켈 Starting out - (5) range, cycle, repeat, replicate 함수 (0) | 2017.12.02 |
---|---|
하스켈 Starting out - (4) 리스트 입문 (0) | 2017.12.01 |
하스켈 Starting out - (2) 함수를 만들어보자 (0) | 2017.11.30 |
하스켈 Starting out - (1) 간단한 수학 연산 (0) | 2017.11.30 |
하스켈 웹프레임워크 - Yesod 라우팅 구문 Routing Syntax (0) | 2017.11.30 |