洪民憙 (홍민희) 블로그

내 블로그의 일관된 논조를 재확인하기 위해 포스팅.

익명 함수와 클로져는 과하게 사용되고 있고, 프로그래밍 언어들이 클로져 하나 대충 던져주고 추상화 컨셉은 다 줬다고 생각하는 것은 프리미티브(primitive)의 가능성(capability)을 추상화 수준으로 착각해서 발생하는 일종의 직무 유기이다. 프로그래밍 언어는 각 상황에 맞는 람다 이상의 추상화 컨셉을 제공해야 한다.

요즘 하도 비슷한 소리를 많이 하게 되어서(사람들이 몇년 전부터 클로져만 있으면 다 되는 줄 안다) 나도 비슷한 쓴소리를 하고 다니게 되는 것 같다. 그래서 비슷한 내용을 얘기한 내 글들을 죄다 다시 링크.

좀더 부연하자면, 실제로 Common Lisp 같은 실용적인 Lisp 언어들 역시 Python이 제공하는 저런 수준의 컨셉들 다 제공한다. 70년대 Lisp 태생기도 아닌데 당연히 아직까지 모든 반복을 재귀로만 짜고 car/cdr/cons로만 리스트 조작하고 살지 않을 뿐더러, 오히려 다른 언어가 지금 수준의 추상화 컨셉들 갖추기 훨씬 이전부터 실용적인 Lisp들은 그런 언어적 도구들을 완비하고 있었다. 메세지 패싱? CLOS 쓰면 된다.

내가 자주 얘기하는 거지만 SICP는 프로그래밍 입문서로 이해하면 안되고 PL 입문서로 봐야 한다. (대체 어떤 프로그래밍 입문서에서 컴파일러를 짜고 VM을 구현하냐?) 당연히 프로그래밍 언어 이론을 배우는 차원에서는 현대적인 언어들이 구비하고 있는 고수준의 각종 추상화 블럭들을 로우레벨 프리미티브로 직접 만들어보는게 무척 도움이 된다. 하지만 C/C++가 Java가 제공하지 않는 포인터라는 저수준 프리미티브를 갖고 있다고 해서 더 고수준 언어가 되는 것은 아닌 것처럼, 익명 함수 던져준다고 그 언어가 고수준이 되는 것은 아니다. (프리미티브가 강력하다는 것은 일반적이라는 것이고 그럼 추상화 수준은 낮은 것이다.)

그리고 프로그래밍 멀쩡히 잘하는 사람들 중에서 SICP 첫부분부터 읽는 사람들도 있던데 Lisp을 전혀 모르는 사람이 아니라면 그냥 중간 이후부터 읽는걸 추천한다. 대부분 첫부분이 어려워서 읽다 마는 게 아니라 지루해서 읽다 마는 건데 어렵다고 착각하는 경우도 있는 것 같다. 가끔 대가들이 별 생각 없이 한 행동에 대해서도 뭔가 큰 의미가 있을 거라고 생각하고 과대 해석하는 경우가 있는 것처럼, 책에도 그런 태도가 존재하는데 SICP도 그런 일이 많이 일어나는 듯하다.

마무리하며 던져보는 얘기. JavaScript의 Array 객체에는 forEach 메서드가 있다. 자, 이걸 써서 반복을 하던 중에 break를 해야 한다면 어떻게 해야 하는가? (continue는 그냥 return을 하면 된다.) 특정한 예외를 정해서 던지면 forEach 메서드에서 그걸 잡는 경우 break를 해주도록 짤 수 있을 것이다. 자, 방금 당신은 언어가 구현해줘야 하는 제어문 하나를 직접 구현했다. 특수한 경우를 위해 언어가 제공하는 추상화 블럭들이 괜히 있는 게 아니다. 거의 항상 그런 특수한 추상화 블럭은 일반적인 추상화 블럭으로 달성하려면 힘들게 구현해야 하는 기능들을 함께 제공한다. 반복하고 싶으면 for문에 continue, break 잘 쓰자. 우리가 break문을 미사용할 직접 구현할 이유가 없다. 근데 JavaScript는 반복 인터페이스가 없으니까 망했음.