갈루아의 반서재

10보다 작은 자연수를 2배로 곱하는 리스트를 만들려면 take 10 [2,4..]와 같은 방식으로 작성할 수 있다. 이와는 달리 list comprehension 을 사용할 수 있는데, 이는 set comprehensions과 매우 유사하다. 아래에서 사용한 list comprehension 즉, [x*2 | x <- [1..10]] 을 보면, x 는 [1..10] 에서 나왔고, 각각의 원소 x에 대해 2배로 만드는 것이다. 

  1. Prelude> [x*2|<- [1..10]]
  2. [2,4,6,8,10,12,14,16,18,20]
  3. Prelude>

그러면 위의 구문에 조건을 붙여보자. 이제 2배를 했을때 12보다 큰 원소만 골라내보자. 다음과 같다.

  1. Prelude> [x*2|<- [1..10], x*2 >= 12]
  2. [12,14,16,18,20]
  3. Prelude>

그러면 50에서 100까지 모든 숫자에 대해서 7로 나누는 경우 나머지가 3인 원소만 골라내보자.

  1. Prelude> [x|<- [50..100], x `mod7 == 3]
  2. [52,59,66,73,80,87,94]

10 보다 큰 홀수는 "BANG!" 으로 그리고 10보다 작은  홀수는 "BOOM!" 으로 대체하는 함수를 만들어보자. 만약 홀수가 아닌 경우에는 리스트에 포함시키지 않는다. 

  1. Prelude> boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]
  2. Prelude> boomBangs [7..13]
  3. ["BOOM!","BOOM!","BANG!","BANG!"]

10에서 20사이의 자연수 중 13, 15, 19가 아닌 것을 골라내려면 다음과 같이 한다.

  1. Prelude> [ x | x <- [10..20], x /= 13, x /= 15, x /= 19]
  2. [10,11,12,14,16,17,18,20]

다수의 조건을 걸 수도 있지만, 다수의리스트에서 원소를 가져올 수도 있다. 다수의 리스트에서 원소를 추출할 때는 가능한 모든 조합을 뽑아낸다. 아래에서 보듯이 각각 3개의 원소로 이루어진 리스트의 경우 총 9개의 원소를 가진 리스트가 생성된다. 

  1. Prelude> [x*| x <- [2,5,10], y <- [8,10,11]]
  2. [16,20,22,40,50,55,80,100,110]
  3. Prelude> [x*| x <- [2,5,10], y <- [4,8,10]]
  4. [8,16,20,20,40,50,40,80,100]

이 중 50보다 큰 값만 골라내려면 다음의 조건을 추가하면 된다.

  1. Prelude> [ x*| x <- [2,5,10], y <- [8,10,11], x*> 50]
  2. [55,80,100,110]

명사와 형용사에 대한 리스트의 경우를 보자.

  1. Prelude> nouns = ["hobo","frog","pope"]
  2. Prelude> adjectives = ["lazy","grouchy","scheming"]
  3. Prelude> [adjective ++ " " ++ noun | adjective <- adjectives, noun <- nouns]
  4. ["lazy hobo","lazy frog","lazy pope","grouchy hobo","grouchy frog","grouchy pope","scheming hobo","scheming frog","scheming pope"]

리스트의 길이를 반환하는 length' 함수를 만들어보자.

  1. Prelude> length' xs = sum[1|<- xs]
  2. Prelude> length[1,2,3,4,5,6,9]
  3. 7

여기서 _ 이 의미하는 바는 변수 이름을 쓰지 않고 해당 리스트에서 원소를 끄집어낸다는 뜻이다. 이 함수는 리스트내의 모든 원소를 1로 반환한 후 그것을 합하게 되고, 즉 리스트의 길이를 반환하게 되는 셈이다. 

문자열은 리스트이기 때문에, 문자열을 처리하고 생성하기 위해 list comprehensions 을 이용할 수 있다. 대문자를 제외한 나머지를 삭제하는 함수를 만들어보자.

  1. Prelude> removeNonUppercase st = [| c <- st, c `elem['A'..'Z']]
  2. Prelude> removeNonUppercase "Hahaha! Ahahaha!"
  3. "HA"
  4. Prelude> removeNonUppercase "IdontLIKEFROGS"
  5. "ILIKEFROGS"

중첩리스트에 대해서도 list comprehensions 을 이용할 수 있다.

  1. Prelude> xxs = [[1,3,5,2,3,1,2,4,5],[1,2,3,4,5,6,7,8,9],[1,2,4,2,1,6,3,1,3,2,3,6]]
  2. Prelude> [[ x | x <- xs, even x] | xs <- xxs]
  3. [[2,2,4],[2,4,6,8],[2,4,2,6,2,6]]

GHCI 환경이 아니라면 여러 줄에 걸쳐 코드를 작성하는게 편하다.