core.match 빠르게 살펴보기

core.match는 뭔가요?

core.match는 패턴 매칭 라이브러리 입니다. 하스켈이나 스칼라 같은 대부분의 함수형 언어에는 패턴 매칭 기능이 있습니다. 클로저는 타입 시스템이나 패턴 매칭과 같은 문법적 기능도 라이브러리로 많이 제공하고 있습니다. 클로저는 문법적으로 단순하고 매크로라는 강력한 확장 기능이 있으므로 언어의 기본 기능은 단순히 유지하고 나머지 확장 기능을 라이브러리 형태로 제공하는 것 같습니다. 그럼 core.match를 빠르게 살펴봅시다!

core.match 사용하기

core.match는 라이브러리기 때문에 사용하시는 의존성 관리 도구 형태에 맞게 의존성을 추가해주면 됩니다. Leiningen 프로젝트인 경우 project.clj 파일 :dependencies 키에 아래 구문을 추가해 줍니다.

[org.clojure/core.match "0.3.0-alpha4"]

아주 간단한 예제

(require '[clojure.core.match :refer [match]])

(let [s [1 2 3]]
  (match s
    [1 2 3] "one"
    [2 3 4] "two"
    :else "?"))

위 코드의 평가 결과는 one입니다. 쉽죠? 그런데 이게 뭐냐고요? case 구문과 똑같다고요?

(let [s [1 2 3]]
  (case s
    [1 2 3] "one"
    [2 3 4] "two"
    :else "?"))

그러네요! case문하고 같네요? 맞아요! case 구문과 비슷하게 동작합니다. 하지만 core.match는 더 다양한 방식으로 매칭 할 수 있습니다. case로 할 수 없는 예제를 살펴보아요.

(let [s [1 2 3]]
  (match s
    [1 _ _] "one"
    [2 3 4] "two"
    :else "?"))

위 예제의 결과도 역시 one입니다. _ 기호는 “어떤 값이든 매칭되어라!”라는 뜻이기 때문이죠. 그래서 값 s가 3개의 항목을 가지는 벡터이면서 첫 번째 값이 1인 경우 나머지 두 값이 무엇이든지 one으로 평가됩니다.

바인딩

패턴 매칭으로 정규식처럼 매칭된 값을 쓸 수 있습니다. 아래 예제를 봅시다.

(let [x 1 y 2]
  (match [x y]
    [1 b] b
    [a 2] a
   :else nil))

위 예제의 결과는 2입니다. 매칭 데이터 부분에 심볼을 사용했는데요. 첫 번째 패턴인 [1 b]는 값이 2개의 벡터로 되어 있고 첫 번째 항목이 1인 경우 매칭됩니다. 벡터의 두 번째 값은 _처럼 아무 값이어도 되는데 그 값이 b 심볼에 바인딩 되어 결과 구문에 사용할 수 있습니다.

나머지 패턴

패턴 매칭을 시퀀스 값에 사용할 때 첫 번째 항목과 나머지 항목을 각각 매칭 할 수 있습니다. 물론 바인딩해서 쓸 수 있습니다. 아래 예제를 살펴 봅시다.

(let [s [1 2 3]]
  (match s
    [x & xs] xs))

위 예제에서 & 기호를 사용했는데요. &는 시퀀스의 첫 번째 항목을 제외한 나머지 부분과 매칭됩니다. 그래서 x 심볼은 첫 번째 항목인 1 값이 바인딩 되고 xs 심볼에는 [2 3] 값이 바인딩 됩니다. 평가 결과는 [2 3]갰죠!

나머지 패턴을 사용해서 다음과 같은 코드를 작성할 수 있습니다.

(defn sum [coll]
  (match coll
    [] 0
    [x & xs] (+ x (sum xs))))

위 예제는 패턴 매칭을 써서 인자로 받은 숫자 시퀀스를 모두 더하는 예제입니다. 물론 (reduce + ints) 하면 더 간단하지만 이해를도우려고 만들어 본 예제입니다.

마무리

core.match 라이브러리로 패턴매칭을 간단히 알아봤는데요. core.match는 좀 더 다양한 방법으로 매칭되는 기능들이 있으므로 더 알고 싶으시면 core.match 위키를 읽어보세요. :)


Eunmin Kim

clojure, emacs