함수형 프로그래밍 언어 3대장
(1) 세상 가장 우아한 코드를 만드는 Clojure, (2) 실무에 도입하기 가장 좋은 Scala, (3) 학계 정통파 순수 함수형 언어 Haskell을 소개합니다.
함수형 프로그래밍의 가치가 널리 알려지면서, Python, Java, JavaScript 같은 명령형(imperative) 프로그래밍 언어에서도 함수형 프로그래밍을 하는 개발자가 많아진 것 같습니다. 대중적인 명령형 프로그래밍 언어에서도 함수형 프로그래밍 스타일로 개발할 수 있습니다만, 훨씬 더 우아하게 함수형 프로그래밍을 하려면, 아예 함수형 프로그래밍 언어를 사용하는 방법도 있겠습니다.
본격적인 함수형 프로그래밍 언어 중에 대중적인 것으로는, 클로저(Clojure), 스칼라(Scala), 하스켈(Haskell)을 꼽을 수 있겠습니다.
최근 몇 년 동안 이 세 멋진 프로그래밍 언어를 다 공부해보게 되었습니다. 첫째로 클로저를 배우기 시작한 다음, 이어서 스칼라로도 프로덕션 코드를 작성했고, 최근에는 하스켈까지 공부하고 있습니다. 아직 잘 알지 못하는 입장입니다만, 이제껏 느낀 점을 공유해보겠습니다. 본격 함수형 프로그래밍 언어에 관심 있는 독자분들께 도움이 되기를 기대합니다.
Clojure | 현대판 LISP
클로저는 LISP라는 독특한 겉모습의 프로그래밍 언어 패밀리 중 하나입니다. 리스프는 포트란과 더불어 이제껏 활용되는 가장 오래된 프로그래밍 언어 중 하나입니다. 리스프는 S식(S-expression)이라고 부르는 괄호로 감싼 표현식을 나열해 프로그램을 짜는 독특한 모양새입니다. 이 괄호식이 여러 번 중첩되고 한꺼번에 닫히는 경우도 있어, 너무 많아 복잡해 보이는 괄호에 거부감을 느끼는 분들도 있습니다.
처음엔 모양새 때문에 놀랄 수 있지만, 결국은 그 괄호식들의 강력한 표현력에 감탄하게 되고, 어쩌면 그 괄호들이 예뻐 보이게 될 수도 있습니다. 사실 그 연속된 괄호는 다른 언어에서 여러 줄에 걸친 중괄호나 end 키워드에 해당하는 것이기에, 실제로 의미를 파악해보면 훨씬 간명한 표현이거든요. 그리고 실제로는 그리 많은 식을 중첩하는 일은 잘 없기 때문에, 너덧 개 이상의 괄호가 한꺼번에 닫히는 일도 흔치 않습니다. 마치 희극인이 유명인의 성대모사를 하듯, 특징적인 무언가를 놓고 과장해서 놀리는 것이라고 생각하면 맞겠습니다.
어쨌건 여닫는 괄호로 악명 높은 리스프 가족 언어들이 클로저 말고도 많이 있습니다. 그중 클로저는 약 15년 전쯤에 탄생한 현대판 리스프이며, 자바 가상 머신 (JVM) 위에서 동작합니다. 따라서 JVM에서의 자바 라이브러리와 상호 운영이 쉽기 때문에, 자바가 널리 쓰이는 실무 환경에서도 쓰기 좋습니다.
클로저에서 S식은 기본적으로 함수를 호출하는 것이고, 그 결과로 어떤 값이 반환됩니다. 명령형 언어들은 어떤 명령을 수행하고, 상태를 바꾸는 기계의 “실행”에 중심이 있다면, 함수형 언어들은, 어떤 결괏값을 “계산”하는 것에 중심이 있습니다. 그래서 모든 식은 결국 어떤 값을 계산해 반환하며, 기계보다는 사람의 관점에 더 가깝습니다.
기계를 위한 명령형 언어 vs. 사람을 위한 함수형 언어
클로저는 함수를 적극적으로 활용하면서, 기본 문법이나 표준 라이브러리가 지연 시퀀스, 불변 존속 자료 구조, 그리고 트랜스듀서 등 매우 유연하고 강력한 함수형 체계가 잘 준비돼 있기 때문에, 클로저를 쓰는 것만으로도, 함수형 프로그래밍을 하는 것에 익숙해지면서 배우기 좋습니다.
또, 클로저는 동적 타입 언어라, 구체적인 타입을 명시하지 않으며, 순수 함수형 언어를 추구하지는 않아서, 어떤 효과(이펙트)를 다룰 때 사용하는 모나드(Monad) 같은 것들은 잘 쓰지 않는 편이라, 배우는 부담이 적은 함수형 프로그래밍 언어입니다.
Scala | 객체 지향과 함수형 프로그래밍 언어의 조화
다음으로, 스칼라는 클로저와 마찬가지로 JVM 환경에서 작동하기 때문에, 역시 현업 업무 환경에서 다른 자바 기반 라이브러리와 함께 쓰기에 좋습니다.
스칼라는 명령형 프로그래밍 세계에서 적극 활용되는 객체 지향 프로그래밍(OOP) 방식과, 함수형 프로그래밍 (Functional Programming, FP) 방식을 둘 다 잘 활용하면 좋겠다는 아이디어에서 출발한 프로그래밍 언어입니다.
객체 지향 프로그래밍과 함수형 프로그래밍이 서로 대척점에 있어서 한 방식만 골라 쓸 수 있을 거라는 오해를 하는 분들도 많은데요, 사실 그렇지 않습니다. OOP를 하면서도 얼마든지 동시에 FP 방식으로 접근할 수 있습니다. 이미 잘 알고 있는 OOP를 잘 활용하면서 FP도 하고 싶다면, 이 글에서 언급하는 세 언어 중 가장 좋은 선택지가 되겠습니다. 두 방식을 혼용할 수 있다는 점을 좋게 보면, 두 세계 모두에게서 사랑받는 언어이고, 나쁘게 보자면 양쪽 모두로부터 미움받는 언어이기도 합니다.
스칼라의 창시자인 마틴 오더스키(Martin Odersky)는 모나드를 적극 활용하게 되는 순수 함수형 프로그래밍보다는, 평범한(plain) 함수형 프로그래밍을 권장하고 있습니다. 한편, 커뮤니티 라이브러리인, 스칼라 cats나 scalaz 같은 함수형 라이브러리를 바탕으로 나름의 생태계가 아주 잘 갖춰져있기 때문에, 스칼라로 개발하면서도 하스켈 스타일의 순수 함수형 프로그래밍을 추구하기 좋은 환경입니다. 스칼라를 활용하는 사람의 기호에 맞게, 얼마나 깊게 함수형 프로그래밍에 접근할 것인가 선택할 수 있다는 장점이 있습니다.
일단 생긴 모양새가 크게 튀지 않으며 친숙하고, 보통의 개발자들이 대부분 익숙한 OOP를 할 수 있다는 점에서, 기존 업무 환경에 도입해 쓰기 좋은 가장 좋은 함수형 언어일 거라고 생각합니다.
Haskell | 정통 순수 함수형 프로그래밍 언어
클로저나 스칼라의 경우에는 각각 리치 히키(Rich Hickey)나 마틴 오더스키(Martin Odersky) 같은 창시자가 있고, 이 분들이 주도적으로 언어를 개발 발전시키고 있습니다만, 하스켈은 독특하게도, 학계에서 위원회(committee)가 출범해서 언어를 만들고 발전시켰습니다. 그 출발점 자체가 함수형 프로그래밍을 위한 공통의 언어를 만들어 보자는 뜻으로 모였기에, 함수형 프로그래밍을 하기 위한 갖가지 기법들이 하스켈 기준으로 시작되거나, 설명된다고 생각하면 될 것 같습니다. 함수형 프로그래밍 세계의 만국 공용어인 거죠.
하스켈은 순수 함수(pure function)로만 프로그래밍을 하며, 이는 곧 부수효과(side effect)를 일으킬 수 없다는 특징이 있습니다. 화면에 텍스트를 보이거나, 네트워크로 데이터를 보내거나, 또는 데이터베이스에 기록을 남기는 작업처럼, 실용 프로그래밍을 한다면 반드시 필요한 부수효과를 일으키지 않는다는 점이 놀랍습니다.
하스켈은 실용적 프로그램을 위해, 물밑에서 “부수효과”를 발생시키는 방식 대신, “효과”를 명시적으로 드러내서 다룹니다. 효과를 명시적으로 다루면, 순수 함수로 실용 프로그래밍을 할 수 있다는 장점을 얻는 대신에 코드를 작성하는 일이 꽤나 번잡해진다는 단점이 따라오게됩니다. 그러다, 이 명시적인 표현의 번거로움을 없애주는 도구로 카테고리 이론이라는 수학 분야에서 나온 “모나드(Monad)”를 쓸 수 있다는 점을 발견해서 활용하고 있습니다.
순수 함수가 뭐가 그토록 대단하기에, 고급 수학 지식까지 들춰가며 모나드를 공부해야 하는 걸까요? 그건 아마도, 순수 함수로 프로그램을 작성하면, 코드 조각조각마다 참조 투명(referentially transparent)하게 되기 때문인 것 같습니다. 참조 투명한 코드는 탄탄한 프로그램의 근본이 되며, 이해하기 쉬운 구조로 코드 조각들을 재구성하는데 자유롭고, 독립적으로 코드를 테스트하기 쉬어지며, 나아가서 프로그램 코드가 올바르다는 것을 증명(proof)할 수도 있습니다.
만약, 모나드를 꼭 이해하고 넘어야 할 장벽이라고 여긴다면, 하스켈이 가장 적절한 선택일 수도 있겠습니다. 나머지 언어들은 모나드를 모르고도 그럭저럭 함수형 스타일로 개발할 수 있지만, 하스켈은 결국 모나드 없이는 실용 프로그래밍이 불가능하기 때문에 어쩔 수 없이 반드시 공부하게 됩니다. 이젠 도망칠 수 없는 배수진이 쳐지는 거죠.
기본특징표
이상 언급한 세 언어의 특징을 제멋대로의 기준으로 정리해보았습니다. 이 표는 논란의 여지가 큰 항목들이 꽤 있기 때문에, 참고차 가볍게 훑어보시는 정도로 넘기시면 좋을 것 같습니다.
마무리
어렵기로 악명 높은 모나드까지 활용할 용기가 나지 않는다면, 클로저나 스칼라에서 접근하는 방식처럼, 일단 부수효과가 있는 위험한 함수와 안전한 순수 함수를 분리해서 작성하는 것만으로도 함수형 프로그래밍의 장점을 누릴 수 있다고 생각합니다.
그중에도 클로저는 어쩌면 가장 아름답고 우아한 코드를 작성할 수 있다는 점에서 매력이 크고, 함수형 프로그래밍을 충분히 맛보면서도 실용적으로 활용할 수 있는 언어입니다. 개발자 사고의 틀을 크게 확장시켜준다는 점에서, 공부해서 개인 프로젝트에 활용해보는 것도 충분한 가치가 있는 언어라고 생각합니다.
스칼라는 현업 환경에서 함수형 프로그래밍을 도입하기에 좋은 언어라고 말씀드려보겠습니다. 이미 많이 익숙한 OOP를 그대로 쓸 수도 있고, 그 모양새도 무난하게 받아들여지기 좋습니다.
하스켈은 정통 순수 함수형 언어로, 순수 함수로도 얼마든지 세상 모든 프로그래밍 작업을 탄탄하게 해낼 수 있다는 실제 사례를 보여줍니다.
이상, 대표적 함수형 프로그래밍 언어 3종을 공부한 지금까지의 느낌을 공유해보았습니다. 셋 언어중에 어떤 언어를 먼저 공부할까 고민하시던 분들께 도움이 되었으면 하는 바람입니다.
감사합니다. 유익하게 읽으셨다면, 구독… 아니 공유!