if, cond, condp, case

내 이 세상 도처에서 쉴 곳을 찾아보았으나, 마침내 찾아낸, 컴퓨터가 있는 구석방보다 나은 곳은 없더라.

if, cond, condp, case

흔히 접하는 프로그래밍 언어에는 if~else if가 연달아 나온다고 해서 코드 모양이 이상해지지는 않는다. 다음 Java 코드와 같이 그냥 순서대로 쓰면 되고 코드를 읽는 것도 어렵지 않다.

if (a == 1) {
  return v1;
} else if (a == 2) {
  return v2;
} else if (a == 3) {
  return v3;
} else {
  return vx;
}

그런데 LISP 계열 언어에서는 if를 이런 식으로 쓸 수 없다. (if test then else?) 형태로 만들어야 하는데 여기에 if를 추가하려면 then이나 else?if 폼을 넣어야 하기 때문에 괄호가 중첩되어 보기 흉한 코드가 된다.

(if (= a 1)
  v1
  (if (= a 2)
    v2
    (if (= a 3)
      v3
      vx)))

다행히 cond를 사용하면 위 코드를 다음과 같이 바꿀 수 있다. cond는 매크로다. 확장하면 위 if로 작성한 것과 동일한 코드가 된다.

(cond (= a 1) v1
      (= a 2) v2
      (= a 3) v3
      :else   vx)

코드를 보면 (= a ?) 패턴이 반복된다. condp를 이용하면 이런 반복도 제거할 수 있다. condp 역시 매크로로 확장하면 위 if로 작성한 것과 동일한 코드가 나온다.

(condp = a
  1 v1
  2 v2
  3 v3
  vx)

predicate이 =이라면 다음과 같이 case를 사용할 수도 있다. case도 매크로이긴 하지만 확장했을 때의 모양이 condcondp와는 다르다. 그러나 실행 결과는 동일하다.

(case a
  1 v1
  2 v2
  3 v3
  vx)

처음에 나온 Java 코드와 비교해보기 바란다. 얼마나 간결한가! Java도 switch~case를 사용하면 코드를 좀더 간결하게 만들 수 있긴 하다.

switch (a) {
  case 1:  return v1;
  case 2:  return v2;
  case 3:  return v3;
  default: return vx;
}

그러나 Clojure의 간결함과는 비교가 되지 않는다.