갈루아의 반서재

하나의 값에 다수의 값을 저장한다는 측면에서 튜플은 리스트와 유사하다. 하지만 몇 가지 근본적인 차이점이 있다. 숫자의 리스트는 숫자의 리스트일 뿐이다. 그 자체가 타입이고 하나의 숫자만 갖느냐 아니면 무한개의 숫자를 갖느냐는 아무런 문제가 되지 않는다. 

하지만 튜플은 결합시킬 값의 갯수를 정확히 알고 있을 때 사용할 수 있다. 얼마나 많은 요소를 포함하고 있고 그 요소의 타입이 무엇인지에 따라 타입 또한 결정된다. 튜플은 괄호로 표시되고 구성요소는 콤마로 구분된다.

다른 주요한 차이점은 구성요소들이 동질(homogenous)의 것일 필요는 없다는 것이다. 리스트와 다르게 튜플은 다양한 타입의 요소를 포함할 수 있다.

하스켈에서 2차원의 벡터를 어떻게 나타낼 수 있을지 생각해보자. 하나의 방법은 리스트를 사용하는 것이다. 그렇다면 2차원의 비행기 형상의 지점을 나타내기 위해 다수의 벡터를 리스트에 넣고자하면 어떨까? [[1,2],[8,11],[4,5]]와 같이 할 수 있을 것이다. 

하지만 위의 방식의 문제점은 [[1,2],[8,11,5],[4,5]]와 같은 리스트도 가능하다는 것인데, 앞의 예를 적용하자면 이건 말이 안된다는 것이다(물론 리스트를 원소로 갖는 리스트이므로 이 자체는 문제가 없다). 하지만 흔히 pair 이라고 불리는 크기가 2인 튜플은 그 자체로 타입이 되는데, 이 말은 크기가 3인 튜플은 포함될 수 없다는 것이다. 표시는 괄호를 이용하여 [(1,2),(8,11),(4,5)]와 같이 표현하면 된다. 만약 [(1,2),(8,11,5),(4,5)] 를 입력하면 다음과 같은 에러가 발생한다. 같은 리스트에 페어와 트리플을 함께 넣을 수 없다는 것이다.

  1. Prelude>  [(1,2),(8,11),(4,5)]
  2. [(1,2),(8,11),(4,5)]
  3. Prelude>  [(1,2),(8,11,5),(4,5)]
  4.  
  5. <interactive>:20:9: error:
  6.     • Couldn't match expected type ‘(t1, t)
  7.                   with actual type ‘(IntegerIntegerInteger)
  8.     • In the expression: (8115)
  9.       In the expression: [(12)(8115)(45)]
  10.       In an equation for ‘it’: it = [(12)(8115)(45)]
  11.     • Relevant bindings include
  12.         it :: [(t1, t)] (bound at <interactive>:20:2)

리스트와 마찬가지로 구성요소끼리 비교가 가능하다면 튜플 역시 비교가 가능하다. 서로 다른 크기의 2개의 리스트는 비교가 가능하지만, 크기가 서로 다른 2개의 튜플은 비교할 수 없다. 페어를 조작하는데 도움이 되는 2개의 함수는 다음과 같다. 

fst 는 페어를 받아서 첫번째 요소를 반환한다. 

  1. Prelude> fst (8,11)
  2. 8
  3. Prelude> fst("Wow",False)
  4. "Wow"

snd 는 페어를 받아 두번째 요소를 반환한다. 

  1. Prelude> snd (8,11)
  2. 11
  3. Prelude> snd("Wow",False)
  4. False

다만, 위의 함수들은 페어에만 적용된다. triples, 4-tuples, 5-tuples 등을 다루는 방법은 이후에 설명한다. 

페어 리스트에 적용할 수 있는 또 다른 함수로 zip이 있다. 2개의 리스트를 받아 매칭되는 원소끼리 조인을 시켜 페어 리스트로 만든다. 2개의 리스트를 결합하거나 2개의 리스트를 동시에 횡단할 때 유용하다. 첫 번째 요소는 첫 번째 요소와 두 번째 요소는 두 번째 요소와 페어링해서 새로운 리스트를 만들어낸다. 

  1. Prelude> zip [1,2,3,4,5] [5,5,5,5,5]
  2. [(1,5),(2,5),(3,5),(4,5),(5,5)]
  3. Prelude>
  4. Prelude> zip [1 .. 5] ["one""two""three""four""five"]
  5. [(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five")]
  6. Prelude>

만약 리스트의 길이가 맞지 않으면 어떻게 될까? 길이를 맞추기 위해 짧은 리스트의 길이에 맞춰 컷팅된다.

  1. Prelude> zip [5,3,2,6,2,7,2,5,4,6,6] ["im","a","turtle"]
  2. [(5,"im"),(3,"a"),(2,"turtle")]

그리고 하스켈은 lazy 하므로,무한 리스트와 유한 리스트를 zip 할 수 있다.

  1. Prelude> zip [1..] ["apple""orange""cherry""mango"]
  2. [(1,"apple"),(2,"orange"),(3,"cherry"),(4,"mango")]

각 변의 길이가 10이하이고, 둘레가 24인 삼각형을 찾는 문제를 풀어보자. 

1) 각 변의 길이가 1에서 10인 모든 삼각형의 조합을 찾는다.

2) 세 변의 길이가 삼각형의 공식에 부합하는 경우만 찾아낸다.

3) 마지막으로 둘레의 합이 24인 경우를 찾는다.

  1. Prelude> triangles = [ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ]
  2. Prelude> rightTriangles = [ (a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2]
  3. Prelude> rightTriangles' = [ (a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, a+b+== 24]
  4. Prelude> rightTriangles'
  5. [(6,8,10)]