이 글은 책 Learn You a Haskell for Great Good!에서 섹션 Case expressions를 읽고 정리한 것이다.
C, C++, Java 같은 명령형 프로그래밍 언어에도 case 문법이 있다. case 문법은 변수를 하나 받아서 그 변수의 값에 따라 미리 정해높은 코드 블록을 실행하는 것이고 보통 마지막에는 정해놓지 않은 나머지 다른 경우에 실행되는 코드 블록을 적는다.
하스켈에도 비슷한데 더 좋은 문법이 있다. 이름을 보면 알 수 있듯이 case 표현식은 if나 let 바인딩 같은 표현식이다. case 표현식은 변수에 올 수 있는 경우의 수에 따라 표현식을 평가하는 것뿐만 아니라 패턴 매칭도 할 수 있다. 함수를 정의할 때도 비슷한 걸 할 수 있었는데 그게 바로 case 표현식의 문법 설탕일 뿐이기 때문이다. 아래 두 코드를 서로 바꿔 쓸 수 있다.
head' :: [a] -> a
head' [] = error "No head for empty lists!"
head' (x:_) = x
head' :: [a] -> a
head' xs = case xs of
[] -> error "No head for empty lists!"
(x:_) -> x
case 표현식의 문법 구조 자체는 정말 단순하다.
case expression of
pattern -> result
pattern -> result
pattern -> result
...
expression이 패턴에 매칭된다. 먼저 첫 번째로 매칭된 패턴이 사용된다. 만약 패턴 매칭에 실패하면 다음 패턴으로 넘어가고 마지막 패턴도 실패하면 런타임 에러가 난다.
함수 인자에 사용됐던 패턴 매칭은 함수를 정의할 때만 쓸 수 있지만 case 표현식은 거의 아무 곳에서나 쓸 수 있다.
describeList :: [a] -> String
describeList xs =
"The list is " ++ case xs of
[] -> "empty."
[x] -> "a singleton list."
xs -> "a longer list."
표현식의 중간에서도 쓸 수 있어서 편하다. 함수 정의에서 쓰는 패턴 매칭이 case 표현식의 문법 설탕이라서 다음과 같이 정의할 수도 있다.
describeList :: [a] -> String
describeList xs = "The list is " ++ what xs
where
what [] = "empty."
what [x] = "a singleton list."
what xs = "a longer list."