옛날에 적어둔 뻘글이 있었는데 여기 사람들은 읽어줄까 싶어서 올려봄. 너무 뻘글이라 근거 보충도 없어서 갤에 올리면 적당하다고 생각했음.
그리고 하스켈을 공격한다고 생각하지 말았으면 좋겠다. 내 스탠스는 하스켈에 대한 호감임. 프로덕션에선 안 쓸 거고.



많은 사람들이 설명하려 했을 테고, 소수의 사람에게 전파되었을 주제. 진지한만큼 재미없는 하스켈.
기존의 자료로는 내가 영향을 받은 slideshare의 Functional Programming Patterns도 있고 하스켈을 빨 결정적 결심을 하게 된 Parsec 라이브러리의 예제 코드도 있다. 솔직히, 하스켈의 모든 걸 자세히 설명하면서 재미있을 자신은 없고, 하스켈의 장점만 보여줄 수 있는 능력 및 뻔뻔함도 없기에 하스켈을 배워온 과정 혹은 좌절기를 써볼까 한다.
첫 하스켈과의 대면은 잘 기억나진 않지만 언어 이름의 희한함에 엔하위키를 찾은 게 처음이 아닌가 싶다. 당시 뇌리에 박혔던 설명은 '프로그래밍 언어의 이론상 최강 및 그 말은 현실은 시궁창?' 위키에 있던 모나드 설명이 이해될 리도 없었고, C계열 언어에 질려버린 난 도대체 어떻게 어려우면 배우는 사람을 좌절시킬 수 있는지라는 가당찮은 호기심으로 배우기 시작했다. 그리고 시작부터 한국어 교본이 없다는 사실에 헛웃음을 흘렸다. 개발자의 항암력으로 Learn you a haskell for a great good을 잡아봤지만, Applicative functor였나 모나드 부분에서 이해가 안 되는 현상을 맞닥뜨렸다. 게다가, 그 책의 반 정도까지 언어 철학에 입각한 "Hello, world"따위 안중에도 없는 순수 계산 문법만 배운 것은 내가 과연 테트리스를 짤 수 있긴 한 건가라는 의심의 시발점이 되었고, 아직도 짤 자신이 없다.
어쨌건 간에 wikibooks haskell 한국어본과 real world haskell이 나중에 있단 걸 알고 그것들을 잡고나니, 어찌어찌 진도는 더 나간 느낌이 든다. 근데 RWH 제본을 가지고 꼼꼼히는 아니더라도 끝까지 읽은 내게 어떠한 보상이 있었는가하면, 없었다. 난 mtl을 배우면 하스켈의 부수 효과를 자유자재로 다뤄 예술적인 코드를 짤 수 있겠노라고 멋대로 기대하고 있었지, mtl도 불편해 다른 이펙트 시스템이 아직도 제안되고 있으며, RWH를 끝까지 읽은 건 너무나 거대한 똥덩어리를 맞닥뜨린 나머지 그게 똥인지도 모르고 있다가 이제사 똥이구나하고 깨달은 느낌이었다. 다시 뒤집어 말하면, 똥이란 것이라도 어쨌든 있긴 하다는 것이며, 치우면 되는 건가하는 기대를 품은 게 현재의 상태고, 나머지 하스켈러도 그런 게 아닐까하고 막연히 추측해 본다. 그도 그럴게 실용 목적으론 정말 토나온다. 지금까지 버틴 독자들에게 경의를 표하며, 왜냐하면 지금까지 1%라도 공감하는 건 조금이라도 배워봐야 가능할 테고, 그렇지 않다면 지루함의 극치를 보장할 수 있으니 말이다.
헌데, 그래서, 하스켈을 모르는 독자들에게 푸념을 그만하고 도대체 어떤 모양과 냄새를 가진 똥이었나 슬슬 설명을 시작해보겠다. 일단 내가 상상하는 엘도라도의 하스켈을 서술하자면 (단점부터 시작하면 슬슬 던져버릴지도 모르니까)
1. OOP는 간단하게 쌈싸먹는다.
엄청난 반박들이 머릿속에서 팽창하겠지만 필자도 어느정도 짐작 중이다. 해서 좀 말해보자면 독자의 생각은 아마 맞을 거고, 나도 뒤에 같은 입장에서 반박할 테니 일단 읽어보자.
당신이 짜는 모든 함수는 C#의 익스텐션 메소드가 될 것이며, 그로 인해 OOP가 추구하는 미덕 중 재사용성 부분에서 크게 압도한다. 혼연 C/C++의 '소프트웨어 위기'절에 따르면 OOP의 등장 배경 및 목적은 안정적인 재활용 및 그에 따른 개발속도 향상이며, 그 특징이 캡슐화, 정보은폐, 추상화, 상속, 다형성으로 정리되어 있다. 이제 설명하려는 방식은, 하스켈 따위 어차피 모를 테니 OOP에서 시작하려고 한다.필요한 기능(알고리즘+데이터)을 집약(모듈화)시켜 재사용 시 편의를 얻을 수 있는 것이 캡슐화라고 요약 가능하겠다. 구체적으로 C++에서의 두드러진 이점으로는 객체명만으로 할 수 있는 작업을 자동완성으로 볼 수 있다. 이게 무시 불가능한 이점임은 반박 불가. 근데, 그럼 C는 모듈화 및 캡슐화가 안 돼있는가? 하고 생각하자면, 사실 모듈화 자체는 헤더 인클루드 만으로 이뤄졌다고 볼 수 있고, 캡슐화로 얻는 이점을 자동완성에 의한 생산성 향상으로 친다면, 그 문제만 해결하면 되는 것 아닌가? 뭣보다 C++의 자동완성은 함수의 첫번째 인자를 객체로 끌어낸 설탕 구문에 가까우니 말이다.
내가 보기엔 하스켈도 마찬가지로 자동 완성이 가능하므로, 꿀리기는 커녕 내 생각엔 능가한다.
두번째 특징인 정보 은폐는 하스켈에선 newtype이라는 간단한 키워드로 전부 해결이 된다. public, protected, private, internal 다 필요없이 단지 쓸 수 있는가 없는가가 중요한 점을 잘 캐치했다고 생각한다. 혹시나 protected를 어떻게 할 건데하고 묻는 독자가 있다면 대답은 모듈을 추가로 만들어 필요한 추상화를 분리하면 된다는 게 현재의 생각이다.
또 하나의 주목점이 있다면 은폐가 심할 수록 재사용은 힘들어진다는 점이다. 여기서 protected를 보자. 엄밀히 보면 이건 공개나 마찬가지고 OOP용어로 IS A와 HAS A관계를 구분한다. 근데 과연 IS A인지 HAS A인지가 중요할까? HAS A지만 IS A의 기능을 원한 적이 과연 없을까. C#의 CookieJarClient를 쓰는 과정이 그렇게 복잡해야만 하나? 하스켈은 protected라는 애매한 개념보다 그냥 가능한가 불가능한가의 문제가 된다.
세 번째 추상화는 보통 인터페이스를 의미하고, 여기서 잠깐 특징들의 관계를 요약하겠다.

뭐 이 글 전부가 근거가 탄탄하진 않은 헛소리로 취급되어도 어쩔 수 없고, 위 관계도는 필자가 봐도 까일 부분이 엄청나겠지만... 넘어가고.
일단 지금 멈추고 관계도를 그린 이유가 나머지 3요소가 현재 관점에서 밀접한 탓인지 하스켈 대응요소로 설명이 힘들어서 그냥 필자 생각 정리하려 한 것이다. 생각이 끝나고 보니 결론이 요약이 되어서 또 결론 먼저 서술하고 나머지 내용을 천천히 알려주겠다.
1. 캡슐화로 얻는 자동완성은 하스켈도 가능할 것 같고
2. 정보은폐는 바람직한 것이지만 상속과 충돌나서 꼬였으며
3. 추상화는 구체화의 반대의미로 결국 타입 시스템과 대응되는데 하스켈에 비할 게 못 되고
4. 상속은 기존 구현의 일부분만 쓰고 싶다는 IoC의 욕망이 비뚤어진 문법으로 표현되었으며
5. 다형성(≒인터페이스)조차 하스켈 타입클래스의 부분집합밖에 되지 못한다.
.. 라는 거다. 정리하고 나니 왠지 또 설명이 귀찮긴 한데.
추상화 자체의 의미만 두고 보자면 당연히 '타입 시그니처'가 되겠다. 함수에서 구현을 빼고나면 남는 것은 선언 뿐. 그리고 이 선언에서 쓰이는 것은 언어의 타입시스템이 되는 것이다. 근데 하스켈의 타입시스템이 어떠나면 C/C++이 우유부단했던 enum의 int호환문제 따윈 없고, 타입 추론이 질질 싸며, (C/C++계열도 가능하지만 하스켈보다 늦었고 특히 하스켈을 필요 최소 부분 빼고는 아예 타입 시그니처를 없애버릴 수 있다.) 함수 전체가 표현식이라 타입 합성 경로만 따지면 원하는 프로그램이 나오는 셈이고, 수학자들이 미친 듯이 연구한 결과물을 가져다 쓰는 거라 Void(C의 void가 아니다)같은 C계열에 존재도 하지 않는 타입도 있고, 어쨌든 우월하다. C에서 IO 함수를 타입 레벨에서 막을 방법은 없으니까.
그래서 이점은? 온갖 최적화 및 린트, 문서화 자동화의 길이 열린다.
네번째 상속은 요즘 C#라이브러리 형태를 보면... 애매할 수도 있겠지만 상속 의존이 적은 편이다. 비교적 최근에 도입된 람다로 콜백 함수를 건네주거나 제네릭, 즉 다형성으로 대개 해결되기 때문이다. 사실 상속이 절실할 정도면 아예 복사해서 새로 만드는 게 더 나을 수도 있는데 하스켈이면 public하게 열어놓고 커리로 인자만 조금씩 바꿔서 최소의 코드로 가능할 거란 막연한 느낌이 든다. 어쨌든 중요성이 떨어지고.
다섯째 다형성은 자바에서 Comparable같은 인터페이스를 짜기 힘들다고 들었다. 필자가 이해한 게 맞는지 좀 확신이 약하나 설명하자면 C로 표현했을 때 첫번째 인자 타입이 고정되어 버리기 때문이다. 하스켈은 애초에 타입 클래스 문법으로 이런 값 의존 방법보다 타입 의존 방법을 쓰고 OOP 디자인 패턴의 어댑터와 유사한 구석이 있어 어댑터 패턴의 존재 의미를 말소시킨다.
이렇게 적어놓고 나서야 빠는 이유 중 대분류 하나가 간신히, 그것도 겉핥기로 끝난 게 얼마나 뭣같은 언어인지에 대한 반증일련지.. 아무튼 계속 진행.

2. 위의 기능들은 OOP 특징 관점이고, 아직 많이 남았다.
왠지 대분류가 2개로 끝나버릴 듯한 맥빠지는 예감도 드는데, 그래도 일단 진행.
1) Function, function, functions
slideshare의 FP자료에서 봤던 문구를 인용해봤다. 의미는 OOP의 기능에 대응하는 하스켈 요소를 의미하는데, OOP에선 SRP를 비롯한 규칙들을 지키기 위해 Visitor 패턴 등을 사용해 생성자의 접근 권한 및 클래스 간 상관관계 등을 고안해야 한다. 생성자, 파괴자, 스태틱, 접근 한정자 등의 세레모니를 함수만으로 해결하게 된다. C++에서 인터페이스 개념을 따로 만들기 싫어서 다중 상속을 만들 정도로 얻으려한 통일성을 하스켈에선 ADT(≒자료형), 함수, 타입클래스로 해결해버린다.(랄까, 사실 이것들밖에 쓸 게 없다), 여기서 포텐셜이 터지는 부분은 하스켈이 람다 칼큘러스라는 수학에 기반해 코드가 곧 표현식이 되어버려 일종의 직렬화가 된다고 받아들일 수 있다. 이 말인 즉슨, 중복의 요체만 잘 잡아내면 대부분 제거가 가능하다는 의미다. 일례로는 루프 추상화나 모나드가 되겠는데 모나드는 처음일테니 예를 들자면 Maybe모나드로 WinAPI 코딩 시 발생하는 if return 떡칠의 해법을 줄 수 있다.
2) 참조 투명성
하스켈의 특징을 열거&정당화 하는것으로 가닥을 잡겠다. 또 요약하자면
1) Function is first-class
2) Referencial transparency
3) Lazy evaluation
4) Strong & Solid Type System
정도가 있는데, 아마 더 많을 거고 일단 여기까지 작성한다.
참조 투명성이란 어떤 이름identifier이 항상 같은 것을 가리키는 걸 지칭하는 용어다. C에선 int x;에 3을 대입하고 나중에 4로 바꿀 수도 있지만 하스켈은 기본적으론 그렇지 않다. 부수 효과side effect라는 게 있는데, 간단히 설명하면 전역변수의 수정 및 입출력같은 제어를 포기한 상태 변경을 뜻한다. C계열 언어들은 모두 부수 효과와 밀접하고, 사실 모든 프로그램이 뗄레야 뗄 수 없는 관계를 가지고 있다.
하스켈은 부수효과를 격리시켜 참조 투명성을 획득하고, 그 결과로 함수의 1등 객체화 및 컴파일 정보 증가, 테스트 능력 향상을 얻는다.
부수 효과가 전혀 없는 것을 순수pure하다고 부르고, 아니면 비순수impure라고 부르는데, 순수 함수는 항상 정해진 결과만 출력하기 때문에 최적화와 디버깅에 도움이 된다. 너무 어렵다면 전역 변수 NO정도로 생각하자.
어쨌든 어떻게 최적화와 디버깅에 도움이 되냐면 C++의 constexpr이 추구하는 컴파일 시간 값 계산이라든가, elm의 시간 여행 디버깅같은 게 가능해진다.
3) 지연 평가
간단히 하스켈은 값이 실제로 필요하기 전까지 연산을 행하지 않고 최대한 미룬다. call by value, reference가 아니라 call by need라는 용어까지 만들었다.
덕분에 무한을 굉장히 쉽게 다룰 수 있게 되었다. 범위 제한이 없는 정수형인 Integer...는 별 상관 없나. 하튼 무한 길이 리스트를 사용하는데 무리가 없다. 결과적으로 무한을 유한하게만 사용한다면 BOF고 뭐고 걱정이 없다.
여태까지 프로그램을 쪼개는 방식(문제의 분석 방식)에 관한 것이었다면, 무한의 사용은 프로그램을 조립하는 방식이 하나 추가된 것이다. 근데 그냥 배열이 generator가 됐다고 생각해도 무방하다.
4) 강 타입 시스템
이건 Bartosz Milewski의 범주론 도입부에 나오는 설명을 요약하게 되겠는데 자바스크립트나 기계어처럼 타입이 없거나 약한 언어보다 강한 게 낫지 않겠느냔 말이다. 기계어는 원숭이도 코딩이 가능하다. 의미있는 결과물이 되기 힘들 뿐이지 나오긴 나올 것이다. 근데 우린 의미있는 결과물을 원할 것이며, 디버깅으로 문제를 찾기보단 컴파일 타임 체킴으로 문제를 찾는 게 훨 바람직하지 않을까.
Tcl이란 언어가 있는데 문법이 13개의 문장으로 요약되는 특징이 있고 단어의 나열이 주가되는 구문 형태는 하스켈과 비슷하지만 문자열 타입 하나밖에 없는 최약타입 언어다. 그 언어로 600줄 규모의 코딩을 했었는데, 변수 명명법에 변수가 리스트 이스케이핑이 몇번 되었는지를 안 적어서인진 몰라도 복수 파일 처리 시에 발생하는 버그를 잡기 굉장히 어려웠다. 이 언어로 코딩하고 나서 C의 타입제약조차 괜히 있는 게 아니란 걸 절감했고, 하스켈은... 반드시 그런 건 아니지만, segmentation fault가 불가능하다. 이거야 닷넷도 그러니 놀라운 게 없는데 LiquidHaskell쯤 들어가면 벡터 길이 검사를 정적 분석까지 끌고 들어오는 기염을 볼 수 있다.

3. 그 외에도 장단점은 아니지만
1) 언어 비교
각광받는 언어로 Rust, Crystal, Clojure등도 있을 텐데, 왜 하필 하스켈이냐고 묻는다면 Rust는 기본적으로 C기반에 하스켈 타입클래스 및 리스프 매크로 등을 조화롭게 섞은 거지 중복 제어에 특화되었다고 보긴 힘들고, 크리스탈은 better ruby인데 식상하니 pass, 클로저는 리스프 계열을 대표하고, Paul Graham이 '프로그래밍 언어의 최종형태는 리스프가 될 것이다'라고 하기도 했고, 짤을 보면 하스켈은 탑의 꼭대기에, 리스프는 구름 위에 있기도 하지만, 그래도 하스켈로 결정했다. 솔직히 둘 다 대규모의 프로그램을 짜본 건 아닌지라 어떤 한계가 있을지 명확하진 않지만, 내가 느낀 인상은 리스프는 뜬구름 잡고, 하스켈은 어떻게든 뜬구름을 끌어내리려는 것 같다. 리스프로는 너무 자유로워서 절차지향 코딩도 가능하고 어떤 언어건 간에 homoiconic한 리스프 형태로 나타낼 수 있을진 모르지만, 난 차라리 올 함수형으로 미덕을 강제하고 하스켈조차 힘들어하는 최적화를 리스프가 가능하다고 보기도 힘들고, 뭣보다 괄호도 보기 싫고, 하스켈의 미덕을 적용할 자신도 없다.
2) 철학
하스켈의 여러 목표 중 하나로 'Success should be avoided at all cost'라는 게 있다. 어떤 일이 있어도 성공은 피해야 한다는 얼핏 납득이 안 가는 말인데, 쉽게 말하면 '호환성 따위 개나 줘버려'라는 뜻이다. 이상론일 뿐이지만 나도 이상주의자라 싫어하진 않는다. 다만 가끔 욕은 나온다.
3) 성격
여러 언어를 대상으로 커밋 당 소스코드 평균을 측정한 포스트가 있었는데, 하스켈이 상당히 적은 편에 들어갔다. 이 말인 즉슨 소스코드 당 표현력expressiveness가 크다는 뜻. 실제로도 문법부터가 매우 간결하다. 다만 평균 소스코드 라인 수로 C에 엇비슷한 규모로 판명이 났는데, 내 생각으론 배터리따위 집어 치워의 특징과 견고한 디자인에 필요한 소스코드 줄 수는 그럼에도 무지막지, 혹은 의존성을 모두 계산할 경우 재활용성이 좋아서인지 의존 패키지가 상당한 지라 그런 듯 하다. 특히 견고한 디자인이란 parsec 소스코드를 의미하는데, 정규식의 바람직한 형태를 목격할 수있다. 바꿔말하자면 언어인데 DSL을 내장하기에 최적화된 언어랄까.
4) 발전 가능성
C++이 발전한대도 다른 언어 stable feature 커버하기에 급급. 차라리 하스켈로 최신 동향 그대로 경험하고 싶었다.

이제 끝. 위 말대로라면 이 글 처음부터 지금까지 쭉 들어왔던 의구심, '그렇게 좋은 언어면 왜 아무도 안 쓰나요?'가 대답이 안 되니 이제 그 답을 공개한다.
사실 지금까지 지껄인 거 다 헛소리, 아 시발 꿈. 현실은 시궁창. 이론만 최강. 진빠지긴 하는데 지금까지 적은 걸 그대로 또 반박해 보겠다.

1.1) 자동완성이 가능하다고 했지 당장 쓸 수 있다곤 안 했다. 적어도 윈도 계열에선 변변찮은 IDE하나 없고 Leksah는 썼을 때 자동완성이고 디버거고 뭐고 심하게 후달리는 느낌. 결국 텍스트 에디터 연동이 되는데 윈도에서 설치가 안 되었다. 생산성을 목표로 하기엔 스택 트레이스조차 디버거 지원이 안 되는 듯 해 뇌 내 디버깅 및 printf떡칠을 해야 했던... 아주 슬픈 상태이다. 오로지 cmd로. 그리고 어순 문제로 완벽하게 마음에 드는 자동완성은 나오기 힘들어 보이기도 하다.
1.2) 정보은폐 문법 자체는 흠이 없는데 자동 완성의 부재가 뭐가 public인지 알기 힘들게 만든다. 일사부재리(...)로 이 건을 넘어가자면, 정보은폐가 지나치게 되어서 문제인 경우도 있다. 슬슬 분위기는 짐작하다시피 IDE지원은 기대하지 않는 게 좋고, 결과적으로 Go to declaration/definition을 쓸 수가 없고, 처음 보는 타입을 맞닥뜨리면 그게 String의 alias라 하더라도 알기가 힘들다. 은폐가 지나치게 훌륭한 경우랄까.
1.3) 타입 시스템이 훌륭한 것 까진 좋은데, 타입 불일치가 발생할 경우 나오는 에러 메시지는 알아먹기가 어렵다고 커뮤니티 내 불만 1순위다. 더 골치아픈 건, 뭐가 문젠지 어떻게 해결해야 할지도 마땅치 않다는 것. 하스켈 학습 시 가장 먼저 크게 맞닥뜨리게 되는 것이다. 낙관적일 수가 없는 게 이미 해 본 실수의 에러 메시지엔 익숙해지긴 하는데, 이놈의 에러 메시지가 가면 갈수록 난이도가 레벨 업한다. 흡사 던전 몬스터 보는 줄.
1.4) 상속도 나름 절차지향적 코딩에서 자주나오는 패턴을 문법화 시킨 거라 적지 않은 편리함과 효율 향상을 경험할 수 있다. 하지만 상속에 정확히 대응하는 하스켈 문법은 찾기 어렵고 타입클래스 혹은 record 덮어쓰기 등의 우회책을 받아들여야 한다. 또 조금 Tcl스럽게도, 당연히 있어야 한다고 생각하는 기능 상당수가 라이브러리로 옮겨가 배울지 말지 고민을 하게 만들어버린다. 그 중엔 lens, vector, parsec, mtl등 딜레마스러운 것들이 많다.
1.5) 다형성은.. 너무 풀어버리면 타입추론이 불가능해질 때가 있다.

2.1) 엄청난 통일성, 미친 간결함, 인정한다. 근데 그만큼 가독성도 슬퍼지는 게 아닌가 하는 생각도 든다.
타입 추론은 좋은데 타입 시그니처가 너무 생략되는, 말하자면 추론을 남용하는 경우가 보인다. C계열이라면 적어도 함수나 메소드마다 인자와 반환 타입이 명백하지만 하스켈은… 함수 자체가 많아져 시그니처를 생략하게 되고 그건 타인이 코드를 읽기 힘들게 한다. IntelliJ처럼 타입 힌트를 IDE에서 제공하면 모를까. 꼭 언어 제약일 필요는 없지만 인자 수 제한과 시그니처 명시는 자동화가 이상적이고 린트 룰 정도는 되어야 한다.
필자가 하스켈을 덜 익혀서인진 몰라도 일단 느끼는 게 가능했다는 점이 하나의 장벽으로 보기 충분해보인다. 뭐 호환성 높은 C코드도 충분히 병맛이지만 하스켈은 제어 구조의 추상화(함수화)마저 가능한지라 처음보는 추상화가 나오면 머리를 좀 싸맬 수 있다. 디자인 패턴 공부하는 셈 칠 수도 있지만.
2.2) 하스켈의 숙적이자 암덩어리이자 필요악인 부수효과를 어떻게 다루느냐의 문제가 있다. 사용자 입장에서야 부수효과를 얻기 위해 프로그램을 실행하기 때문에 피할 수 없고, 기대를 줄이지 않는 한 필요한 부수효과의 총량이 변하는 것도 아니다.
하스켈이 도와주는 부분은 순수 계산과 통제를 벗어나는 부수 효과 발생의 경계를 명확히 하고, 원한다면 순수계산의 범위를 넓히도록 도와준다. 다만 지금은 비순수 계산의 수단으로 IO 모나드를 사용하는 데 모나드 자체가 한 번에 한 가지 일 밖에 못하기 때문에 다른 모나드와 혼용하기(섞기) 번거롭다. 현재 대안(extensible-effect, freer-effect, polysemy…)이 여럿 나오곤 있지만 현재도 나오고 있는 만큼 만족스러운 건 없는 듯.
간단히 말해서 하스켈 책 하나 읽고 테트리스를 짤 수가 없다. 빠요엔 말고는.
2.3) 지연 평가는 발상은 좋은데 계산을 끝까지 미루고보니까 메모리를 미친듯이 잡아먹는다. 컴파일 언어니 프로그래머로썬 C정도의 최적화를 기대하지만 하스켈에 있어 성능은 일단 우선순위는 아닌 듯. 하기사 4단계의 변환에서 디버깅 심볼 유지부터가 기적이긴 하다만. 그리고 하스켈의 String = [Char]은 성능 면에서 두고두고 이슈거리다.
CPS를 쓰면 Lazy하면서도 메모리 사용량이 적던데, 자동으로 CPS로 변환하면 안 되는 것인가 하는 의구심도 들고(사실 뒷사정이 이해가 안 가는 건 또 아니다만) 여러모로 성능 추구하기 뭣같은 장애물이 많다. 개발자 입장에서야 자세한 메모리 제어를 생략했으니 컴파일러가 찰떡같이 알아들어서 효율적인 할당을 해 줬으면 좋겠지만 당장 c9에서는 하스켈 플랫폼이 단지 메모리 부족(...)때문에 설치가 불가능. (이 글을 배포하는 시점에서 c9이란 게 없다;;)
요새야 GHC 8.0에 Strict모드를 추가한다는 얘기도 있지만 어쨌거나 아직은 없는 거고 효과도 아직 미지수. 결국 엄격한 평가를 하려면 언어확장을 써서 소스코드에 느낌표를 촘촘히 박아주거나 deepseq, parallel 라이브러리를 동원해 평가 전략을 추가로 삽입해야만 한다.
2.4) 생각해보니 추상화 부분하고 좀 겹치지 않나 싶기도 하다, 일단 중복되지 않게 지적하자면 강타입이 좋은지 약타입이 좋은지에 대한 정답은 나오지 않은 상태다.
조금 약타입 선호자들을 대변해보자면 현실에선 프로그램이 자주 변하는 경우가 많고 그 경우 타입 시그니처 자체가 리팩토링에 부담으로 작용하는 경우도 있다. 시간이 금인데 그걸 하나하나 수정하고 있기 힘들다는 것이다. 물론 어느정도 자동화는 가능하지만 그건 가능한 언어들의 경우고 그마저도 완전하지는 않은 게 현실. 물론 이상적인 (IDE 지원이 완벽한) 경우에는 문제가 없겠지만 이게 바로 가능성을 본다는 의미가 된다.
설령 리팩토링이 자유자재로 가능하다 해도 타입 제약이 복잡해질수록 초보 개발자를 영입하기 요원해진다. 하고자 하는 일이 간단해도 이미 성립된 많은 제약 조건을 지켜가면서 코딩하는 건 전문적인 지식을 요한다. 초보 개발자가 패치를 해야하는데 적절한 수정위치를 찾는데 시간이 걸리고, 타입 안전하게 수정하는 데 알아야 하는 함수가 6가지가 된다면… 금융권에선 납득할지도 모르지만.
즉 강타입이 그다지 장점이 되지 않는 상황이 있다는 것이다. 이 부분은 독립된 주제로도 더 양이 많은 부분이어서 여기까지.

3.1) 그래도 C/C++/C#/Java는 이길 수 없다
드보락이 편하다고 사람들이 써주는 것도 아니듯이, 단순히 익숙함의 문제를 넘어 협업 가능성, 라이브러리의 성숙도, 이식성, 문서화 정도, 최적화 문제 등은 거의 대부분의 비주류 언어의 넘사벽이다. C++이 C와의 상당한 호환성, C#과 자바는 문법의 친숙함 및 편리함으로 사용자 층이 이미 두터워진 상태다. 하스켈은 이런 익숙함의 도움따위 기대할 수 없고, 결과적으로 입문자 부재 → 위에서 언급한 여러 핸디캡 초래 → 입문자 부재의 악순환 중이다. 굳이 하스켈만 그런 건 아니고 그렇게 절망적인 것도 아니라 원래 그런 거지만, 한국어 자료가 부족하다든가, 커뮤니티가 없다든가 하는 문제가 작은 것도 아니다.
하스켈로 짜도 남들이 읽을 수 없고 (최소한 우리나라에선?) 고용되지도 않으며, GUI를 짜는 방법이 상당히 제한되고, 바인딩 라이브러리가 없으면 직접 짜야하며, 어지간한 플랫폼은 GHC가 지원해주겠지만 NDK만큼의 안드로이드 지원이 될 지 기대하기도 어렵고, 패키지 자체는 많지만 그 중 80%는 문서화가 안 되어있을 것이며, 성능문제는 이미 언급한 바가 있고, 루비도 사용자 층으로만 보면 하스켈보단 나을 듯 한데 그럼에도 크롬의 V8 자바스크립트 엔진은 넘지 못했다. 이것도 30년차 VM개발만 판 구글 개발자가 투입돼서 나온 결과인데 루비하고 최적화 방향이 질적으로 다른 하스켈에 얼마나 많은 시간과 인력과 행운이 필요할지.
3.2) 윈도가 널리 쓰이는 이유로 호환성을 버릴 수 없다. 특히 스타처럼 킬러 앱들은 애초에 MS쪽에서 각별히 주의할 정도. GHC 7.10의 Applicative Monad Proposal이 생긴 이유를 조사하거나 하진 않았지만 어쨌든 상당한 기존 코드를 리젝트할 변경도 저질렀다. 하스켈 표준 라이브러리야 상당히 stable하다고 볼 수 있지만 너무 변하지 않은 나머지 대안 표준이 쏟아졌고 그걸 표현하는 xkcd 짤도 나와버렸다. 게다가 head, tail같은 기본적인 함수가 바람직하다는 문제점도 있어 breaking change가 나오는, 혹은 나와야하는 게 아닐까 하는 생각이 들곤 한다. 상당히 안쓰러운 취급의 호환성. 애초에 본격적으로 짜려면 언어 확장을 주렁주렁 달아야 하기도 한다.
3.3) 통계적으론 우월한데, 역시 소스코드 양의 폭발원인을 분석해보자면 디자인(≒미학, 견고함)에 집착하는 하스켈의 특성과 언어 자체도 적당적당히 넘어가는 게 힘들어(러스트도 살짝 그렇지만) 자연스레 그렇게 된다. 그렇게 목적지에 도달한 코드는 계산 자체가 DSL화 되어 견고한 동시에 양이 폭증하는 게 아닌가 하다.
3.4) 가능성 하나보고 빨고 있는데, 한 30년쯤 후에 다시 태어나면 안 될까.