Rosetta Lisp in OCaml
最初に書いたので、移植の上で困ったことといった観点での比較がない。またわりとHaskeller視点での感想になる。
OCamlはReal World OCaml (v1)を読んで始めた。OCamlはHaskellと並んで静的型付けの関数型言語の老舗という雰囲気の言語で、カリー化を前提とした関数適用と演算子の構文や、immutableなリスト、タプル、レコード型、Option型などのデータ型はHaskellとよく似ている。実際Haskellを書いていた経験によってOCamlもわりとすんなり始められた。
しかし表面がHaskellに似ているからといって思想もそうというわけではなく、OCamlは、なんというかずっと手続き型言語的というか、素直、愚直、単純明快、泥臭い、といったことが言えるように思う。OCamlもHaskellもステートレスで宣言的なプログラミングを好むが、OCamlでは普通に関数が副作用を持てる。レコードはmutableなフィールドを持つこともできる。OCamlは高度な型システムを以って副作用を型で表現したり、といったことを目指さない。ocalispの実装も、素朴な実装、という感じに収まっている。
OCamlは定義の後方参照ができない。Cのような前方宣言も存在しない。今主流のプログラミング環境から見るとこれはかなり驚かれることだろう。必然、OCamlではコード全体での依存関係をよく練ったり必要なシグネチャを考えることが強制される。この言語デザインもありOCamlはコンパイルが爆速でもある。スッキリとした依存関係が構築できるのが良いのだけれどocalispでは vm.ml がグチャっとしている... OCamlプログラミングでもう一つ特筆すべきところにモジュールがある。OCamlではプログラムの構造化の単位はモジュールである。モジュールをベースにしたプログラミングは個人的に非常に気に入っていて、
1モジュール1データ型主義に従うと、あるデータ型に対してどのような操作が行えるのかというのがモジュールのシグネチャから非常に読み取りやすい。例えばsexp.mliを見ると、S式のデータ型 t の構造がどのようなもので、S式のリストからの構築・リストへの分解、bool値としての評価、文字列への変換が行えることがわかる。 型の実装の詳細への意識が小さい。曖昧な表現だが....典型的なオブジェクト指向言語で、実装がカプセル化されているもののトップレベルにまず class や struct といったデータ構造のセマンティクスに関わるワードが出てきたり、レシーバを伴うメソッドがあったりレシーバを伴わない静的メソッドがあったり、コンストラクタがあったりというのがライブラリを利用する側には難しいと感じる (これは勿論クラスの継承とかで必要なデザインなのだが...)。OCamlではまずモジュールがあり、モジュールの代表的な型として t があったり関連する例外があったり、あるいは無かったり、という形になる。
パース処理はよく枯れていて使いやすい ocamllex menhir で。
他、OCamlでは標準ライブラリが貧弱で、標準ライブラリの代替がよく使われている。Real World OCaml (v1) でもそのうちの一つ JaneStreet Core を使っている。RWOを読みつつJaneStreet Coreを使わなかったのはCoreがfull-featuredで今回の目的には大きすぎると感じたためだが、現在はJaneStreetが Base という外部依存のないより小さな標準ライブラリを切り出していて、一度試してみたいところ。執筆中っぽいRWOの2nd editionもこのBaseを使っている。