あどけない話

インターネットに関する技術的な話など

Haskell から見た node.js

誤訳

以前、「サーバサイドJavaScriptのNode.js、最初はCやHaskellを検討し失敗。開発者ライアン・ダール氏へのインタビュー」という記事が twitter で話題になっていました。

―― なぜJavaScriptを選んだのでしょう?

ダール氏 実は最初は違いました。最初はC、LuaHaskellなどで失敗していました。そんなときV8(Chromeが採用しているJavaScriptエンジン)に気がついて、やろうとしていることに対してJavaScriptが完璧な言語だと突然ひらめいたのです。

ただでさえ、Haskell は遅いと誤解されているのに、このような悪意さえ感じらえる訳だと、さらに誤解が深まりそうです。原文にはこう書かれています。

Dahl: Originally I didn’t. I had several failed private projects doing the same on C, Lua, and Haskell. Haskell is pretty ideal but I'm not smart enough to hack the GHC.

省略された部分を訳すと「Haskell はかなり理想的なんだけど、僕はGHCをハックするほど頭が良くない」となります。全然印象が違いますね?

Haskell の方が速い

node.js は C10K 問題を解決していると言われています。実際問題として十分な速さなのかもしれませんが、Haskell と比べると遅いのも事実です。

僕の経験では、ネットワークのコードを Haskell で書くと、C と同等かそれ以上の速度が出ます。興味がある人は、以下のスライドを見て下さい。

ユーザスレッドの方が見通しがいい

コールバックスタイルでコードを書くと、プログラムがぶつ切りになり、見通しが悪くなります。また、複雑なロジックを入れようとすると、コールバック地獄に陥ります。「Node.jsとは何だったのか」では、コルーチンを使ってこの問題を軽減しているフレームワークもあることが紹介されていました。

率直にいって、それならやっぱりユーザスレッド(グリーンスレッド、軽量スレッド)の方がよくないですか? コールバックと比べるとはるかに見通しがいいですし、コルーチンのように自分でコンテキストスイッチする必要もありません。

Haskell の入出力関数は、すべて non-blocking で書かれていますので、誤って block してしまうことも起こりにくくなっています。ユーザスレッドは、すでに古典的な技術に属しますが、Haskell では心地よく統合されているのが素晴らしいのです。

Runtime Support for Multicore Haskellによれば、Haskell のユーザスレッドのオーバヘッドは、15ワード+スタック+αです。入出力を起こさないなら、10万個生成しても問題ありません。(Erlang の軽量スレッドも同様でしょうね。)

さらに先を行っているHaskell

Haskell で今一番ホットな話題の一つは、Enumerator/Iteratee です。

もともと関数プログラミングでは、間違いようのない小さな関数を書き、それらを合成することで大きな関数を作ります。関数型言語では、関数自体がモジュール(部品)なのです。

しかし、入出力が絡む場合は、命令プログラミングと同じような感じでコードを書く必要がありました。しかし、Enumerator/Iteratee が登場したおかげで、生産者と消費者を独立に書き、それらを合成することで大きなプログラムを構成できるようになりました。Haskell コミュニティでは、これは大きなパラダイムシフトだと捉えられています。

前出の Yesod も Enumerator/Iteratee を使っています。Enumerator/Iteratee に興味がある人は、以下が参考になるかもしれません。