ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Functional programming languages: F# vs Haskell
    카테고리 없음 2020. 11. 7. 06:27

    90년대에 샀으니 복사본일 것이다.

    지난 시절 Object-Oriented Programming (OOP)가 유행이었지만 그리 대단한(?) 것은 아니라고 생각하는데, 사실 Haskell은 OOP를 전혀(?) 지원하지 않지만 OOP를 감히 딱 한줄로 요약하는 것 같다, "OOP는 function call을 infix operator 형태로도 쓸 수 있다는 것에 불과하다". 즉, f(a, b) 대신 a.f(b)로 쓸 수 있다는 것인데, Haskell에선 이미 infix function call을 지원해서 이를 a `f` b로, infix 형태로 쓸 수 있다. 즉, OOP는 syntactic rule에 불과하다는 관점.

    그러면, data hiding이나 inheritance (그리고 그에 따른 polymorphism)은 어떡하냐고 할텐데... data hiding은 non-pure하지만, (State) monad의 일종으로 볼 수 있을 것 같다. 하지만 inheritance는... 미안하지만 Haskell에선 "완전" 무시다, "static-typed language에서 type은 compile 시에 무조건 결정되어야지... runtime 시에 parent class type으로 혹은 child class type으로 type이 변하는 것은 제대로 된 static typing이 아닐 뿐더러, virtual function table 같은 runtime overhead를 벗어날 수 없다."

    그렇다고 Haskell이 polymorphism을 지원하지 않는 것은 아니고 (polymorphism이 없다면 그건 functional programming language가 아닐 것이다), inheritance와 같은 runtime overhead가 필요한 polymorphism은 지원하지 않는 대신, parametric polymorphism과 ad-hoc polymorphism을 지원한다.

    Haskell에서 generic programming은 parametric polymorphism이라고 불리는데, C++ template function definition과 일단 비슷하다. Haskell에서 별다른 type 지정 없이 f(x) { return x; } 처럼 쓰면 (정확히는 f x = x), 사실 template <class T> T f(T x) { return x; }처럼 정의가 된다. 즉, x가 가능한 type을 모두 열어두고 일단 컴파일을 하되 컴파일이 끝나는 순간에는 f(x)를 call하는 코드는 반드시 x가 구체적인 하나의 type으로 결정되어야 하지, 이를 더 연기하여 runtime 시에 결정되도록 내버려 두지는 않는다.

    그러면, inheritance같은 환상적인 개념(코드 중복을 최소화하는)을 어떻게 적용하고 있는지 궁금할 수 있는데, 이는 OOP 언어임을 주장하는 Rust도 마찬가지로, inheritance를 인정하지 않고 있다. 대신, type class라고 해서(Rust에선 trait라고 불리는) "일종의 하지만 훨씬 체계적인" operator overloading으로 지원하고 있다. 이 경우 생기는 polymorphism을 ad-hoc polymorphism이라고 하는데, 예를 들어 +가 정수 타입과 실수 타입에 모두 쓸 수 있지만 실제로는 서로 다른 definition의 코드가 적용. ML과 (초기?) F#에선 이 type class를 지원하지 않기 때문에 두 버전의 + 연산이 있는데, 정수형에 쓰이는 +와 실수형에 쓰이는 +.으로 구분되었다. (요즘의 F#에선 이 귀찮은 문제를 해결한 것 같은데 type class를 받아들인 것인지 아니면, strong-typed language임를 던져버리고 C처럼 implicit conversion을 쓴 것인지 잘 모르겠다. 하지만 그리 궁금하지 않다. ^^;)

    처음 ML과 Ocaml을 접하고 신선한 충격을 받았다가 Microsoft가 F#을 .Net과 통합하려는 것을 보고 Haskell로 점차 넘어가게 되었는데 그후론 ML과 Ocaml을 쳐다보지 않았다. Programming language가 특정 OS에 종속되는 것을 보는 것이 별로 내키지 않아서...

    개인적인 생각이지만, Microsoft는 F#을 독점하면 안 되었다. 그 때문에 ML까지 함께 죽게 생긴 것 같다. 차라리, 도무지 건드릴 수 없는 C++처럼 그냥 내버려 두든지, 아님 좀 더 기다리면서 천천히 Haskell이나 Rust를 뒤에서 지원하는 게 (독점이 아니라) 옳지 않았을까 싶다, Mozilla처럼. 그리고, 어찌보면 ML도 요즘 안타까운 것 같다. 함수급 언어라고는 하지만 (물론 Haskell처럼 pure하지는 않다) lazy evaluation을 지원하지 않는 이상, 요즘의 Rust와 (혹은 Python과) 딱히 구별될 수 있는 장점이 사라진 것 같다.

    Microsoft가 지금까지 만든 것 중 딱 하나 마음에 드는 게 있는데, Microsoft Lisp다. (게다가 어셈블리어로 만들어져 정말 빠르다.)

Designed by Tistory.