내 블로그의 일관된 논조를 재확인하기 위해 포스팅.
익명 함수와 클로져는 과하게 사용되고 있고, 프로그래밍 언어들이 클로져 하나 대충 던져주고 추상화 컨셉은 다 줬다고 생각하는 것은 프리미티브(primitive)의 가능성(capability)을 추상화 수준으로 착각해서 발생하는 일종의 직무 유기이다. 프로그래밍 언어는 각 상황에 맞는 람다 이상의 추상화 컨셉을 제공해야 한다.
요즘 하도 비슷한 소리를 많이 하게 되어서(사람들이 몇년 전부터 클로져만 있으면 다 되는 줄 안다) 나도 비슷한 쓴소리를 하고 다니게 되는 것 같다. 그래서 비슷한 내용을 얘기한 내 글들을 죄다 다시 링크.
어떤 사람이 Python에서
def
가 표현식이 되거나 이미 표현식인lambda
가 여러 문장을 포함할 수 있게 되었으면 좋겠다고 한 얘기에 대해 내가 한 답변: http://www.reddit.com/r/Python/comments/sjixj/code_blocks_anonymous_functions_in_python/c4ejzsa.누가 SICP 앞부분에 나오는 내용을 보고 Python에도 람다가 있으면 이런 식으로 짤 수도 있다고 쓴 글에 대해, 그건 Python은 이미 언어 차원에서 제공해주고 있는 컨셉들인데 SICP에서 다시 짠 거일 뿐이고 필요 없다고 한 나의 답변: http://www.reddit.com/r/Python/comments/rsse4/if_python_had_lambdas_xpost_from_rlisp/c48dcwp.
좀더 부연하자면, 실제로 Common Lisp 같은 실용적인 Lisp 언어들 역시 Python이 제공하는 저런 수준의 컨셉들 다 제공한다. 70년대 Lisp 태생기도 아닌데 당연히 아직까지 모든 반복을 재귀로만 짜고 car
/cdr
/cons
로만 리스트 조작하고 살지 않을 뿐더러, 오히려 다른 언어가 지금 수준의 추상화 컨셉들 갖추기 훨씬 이전부터 실용적인 Lisp들은 그런 언어적 도구들을 완비하고 있었다. 메세지 패싱? CLOS 쓰면 된다.
내가 자주 얘기하는 거지만 SICP는 프로그래밍 입문서로 이해하면 안되고 PL 입문서로 봐야 한다. (대체 어떤 프로그래밍 입문서에서 컴파일러를 짜고 VM을 구현하냐?) 당연히 프로그래밍 언어 이론을 배우는 차원에서는 현대적인 언어들이 구비하고 있는 고수준의 각종 추상화 블럭들을 로우레벨 프리미티브로 직접 만들어보는게 무척 도움이 된다. 하지만 C/C++가 Java가 제공하지 않는 포인터라는 저수준 프리미티브를 갖고 있다고 해서 더 고수준 언어가 되는 것은 아닌 것처럼, 익명 함수 던져준다고 그 언어가 고수준이 되는 것은 아니다. (프리미티브가 강력하다는 것은 일반적이라는 것이고 그럼 추상화 수준은 낮은 것이다.)
그리고 프로그래밍 멀쩡히 잘하는 사람들 중에서 SICP 첫부분부터 읽는 사람들도 있던데 Lisp을 전혀 모르는 사람이 아니라면 그냥 중간 이후부터 읽는걸 추천한다. 대부분 첫부분이 어려워서 읽다 마는 게 아니라 지루해서 읽다 마는 건데 어렵다고 착각하는 경우도 있는 것 같다. 가끔 대가들이 별 생각 없이 한 행동에 대해서도 뭔가 큰 의미가 있을 거라고 생각하고 과대 해석하는 경우가 있는 것처럼, 책에도 그런 태도가 존재하는데 SICP도 그런 일이 많이 일어나는 듯하다.
최근에 블로그에 올렸던 글: 익명 함수의 과한 사용.
그리고 저 모든 것들을 포괄하는 얘길를 좀더 일반화해서 썼던 글: Capabilities, primitives and levels.
마무리하며 던져보는 얘기. JavaScript의 Array
객체에는 forEach
메서드가 있다. 자, 이걸 써서 반복을 하던 중에 break
를 해야 한다면 어떻게 해야 하는가? (continue
는 그냥 return
을 하면 된다.) 특정한 예외를 정해서 던지면 forEach
메서드에서 그걸 잡는 경우 break
를 해주도록 짤 수 있을 것이다. 자, 방금 당신은 언어가 구현해줘야 하는 제어문 하나를 직접 구현했다. 특수한 경우를 위해 언어가 제공하는 추상화 블럭들이 괜히 있는 게 아니다. 거의 항상 그런 특수한 추상화 블럭은 일반적인 추상화 블럭으로 달성하려면 힘들게 구현해야 하는 기능들을 함께 제공한다. 반복하고 싶으면 for
문에 continue
, break
잘 쓰자. 우리가 break
문을 미사용할 직접 구현할 이유가 없다. 근데 JavaScript는 반복 인터페이스가 없으니까 망했음.