興味の対象は、各種プログラミング言語(Ruby,Squeak Smalltalk, Objective-C,OCaml,など)、WebObjects, rails, Linux、Mac、数学、音楽、写真(特に VR)、猫などです。ツッコミは短く鋭く愛を込めて(出典:たださんの日記)。リンクはどうぞご自由に。
アンテナでの更新チェックには、antenna.lirs か、index.rdf をご利用ください。
スタッフをしないRubyKaigiに参加したのは実に5年ぶりぐらい。 大変楽しませて頂きました。
一度スタッフをやってから一般参加者として参加すると、 スタッフの偉大さがものすごくよくわかった。 スタッフの皆様には感謝してもしきれないぐらい。 参加費もうちょっと高くてもいいぐらいです。
弁当とか飲み物配布とかすごく大変なんだろうと想像しますが、大変満足度が 高かったので可能なら続けてもらえると嬉しいです。 今回、公式の懇親会というのはなかったですが、弁当の時間に割とまったりと他のRubyistたちと コミュニケーションとれました。 3日間、同じ空間で一緒に飯を食うというのは一体感が生まれて良いですよ。
あと急なGithubドリンクアップも本当に良かったです。あれだけの人数を 無料で招待だなんて凄過ぎます。
同時通訳も事前の準備などすごく大変そうでしたが、 本当に評判が良かったみたいですね(ここは自分では判断できないので Twitterなどからの伝聞ですが)。
今まではマイクフォローなども各会場に2人ずつ配置して、質問があがったらすぐにそこまで マイクをもって走っていく、みたいな感じでしたが、今回は1人でマイクフォローをやっていたようです。 今までに比べると、質問者にマイクが到着するのに多少時間はかかってましたけど、その分 発表者の人が協力して前の方の席の人には発表者がマイクを渡す、みたいな場面がたまに見られて、 発表者と参加者が近くなるような雰囲気が生まれていて良かったと思います。
レポートも全セッションではなくて主要なもののみにしていたようですが、それで十分だと思います。 (動画の公開だってあるわけですし)
Tシャツやバッグの配布なども「ドサッと置いてあるから、各自持って行って」というゆるーいやり方で 大変良かったと思います。
というように、全体的に今までに比べてだいぶ力を抜いてゆったり運営している感じがすごく良かったと思います。 (それでもまだまだだいぶ大変なんだろうとは思いますが)
おかげさまで、帰って来てから日記を書く体力と精神力が残って、こうして日記を書けています。
では個人的に印象に残った発表に一言コメント。
割と concurrency の話が多かった気がしますが、個人的には concurrency 方面であまり困ってないので、 concurrency 成分は少ないです。
英語での挨拶や司会、本当に大変だったと思います。素晴らしかったです。
プログラミング言語が国境を超えたコミュニケーションツールであり、 絵というのも同様だ、という素晴らしいメッセージでした。 世界中にユーザーが拡がっていて、各国語にサイトを翻訳しているのもすごいと思いました。
あとチャットとかコミックみたいなサービスもやっているのですね。知りませんでした。 (すみません、そっちの業界には疎くて...)
いつも通り、技術的に興味深い話をものすごくわかりやすく冗談を交えながらゆっくり話してくれて 非常に楽しめました。
Web+DB Pressなどでもよく記事を拝見していたので、初めて聞く話というのはそんなに無かったですが、 それでもいくつか忘れていたり、勘違いしていたりした箇所に気付けたので良かったです。
「このコードとこのコードどっちが早いと思います?」って会場に手を挙げさせて、 「実はこっちでしたー」ってやつが面白かったです。
あと、hamlは遅いけど、結局1回しかコンパイルされないから遅くても大きな問題にはならない、 みたいな話がすごく役に立ちました。
昔札幌でも @mrkn 主催で Ruby のソースコードを読むって勉強会をやっていたので、 いろいろ共感しました。
プレゼンの内容も vim でどんどん tag jump してソースを読んでいくという内容で、 やったことない人には大変参考になる内容だったと思います。
Emacs ユーザー視点でも 「vim だとこんな感じなんだなー」というのがわかって 面白かったです。
プレゼンの後のランチのときに少し話させて頂いたのですが、ものすごく親切で 丁寧に教えてくれたり、話してくれたりして嬉しかったです。
RubyConf.tw に行きたくなりました。
Railsの改良にいろいろな提案をして、採用されたり、リジェクトされたり、という話。 リジェクトされたものについても、個人的にはどれも素晴らしい改良だなぁ、と思いました。
merb っぽい引数の扱いとか、validationをブロックで書けるようにとか本当素晴らしいと 思います。
これ本当に良い企画だなー。毎年連載して欲しいです。
コミッターとコミュニティが近くなる感じがします。
コミッターのコードレビュー(?)みたいな感じ。
2011から(?)の連載物。これもコミッターの個性が見られたり、 コミッター間のやりとりが見えて、すごく好きだなー。 毎年やって欲しいです。
みんなで hug の格好で写真を取るという活動。こういうの楽しい。
私が今まで聞いた DCI 系の話の中で一番問題点とその解決策が整理されていてわかりやすかったです。
個人的には今回一番楽しみにしていた発表です。自分の業務に一番近そうな話でした。
Netzke は期待以上に素晴らしいフレームワークでした。ぜひ試してみたい。
「想像するな、思い出せ」ってのが明確で良かったです。
Smalltalk とか Prolog の話w
NewSpeak って言語は初耳だったなぁ。
今回の RubyKaigi で一番笑いました。本当に面白かった(全く役には立ちませんが)。
これに応募したり入賞できる人のことは心の底から尊敬します。
技術的に高度なことがわからなくても、 Ruby の開発には貢献できるんだよという話。
実際にどうやって作業しているかを丁寧に見せてくれました。 私にもできそうな気になりました。
3日間の RubyKaigi の最後にこの話かーw もう私の脳のライフはゼロですw
同時通訳の人もだいぶ辛そうな感じがしたw
聴衆に辛さと苦しさとそれを克服するという達成感を疑似体験させるという大変高度な 素晴らしいコンテンツでした。
聴衆の我々は1時間でもだいぶ辛かったのに、これを何ヶ月にも渡って克服したなんて、 この努力には本当に頭が下がります。
普段に比べて、脳も体もだいぶ疲労していると思うのですが、なぜか夜は興奮して寝れなくなるんですよねー。 毎日寝不足でしたけど、それでも楽しめたので相当楽しかったのだと思います。
スタッフのみなさま、発表者のみなさま、スポンサーのみなさま、本当にありがとうございました。
何をやるのかよくわかってませんでしたが、ノリで参加登録して参加してきました。
LT大会とか、dRubyやRailsGirlsのハンズオンが行われていました。
だいぶゆるーい感じで、3日間の疲れた脳を癒すリハビリ場として大変良かったです。
最初は結構ちゃんと LT 聞いたりしていたのですが、午後からはほとんど通路で 他の Rubyist としゃべってました。
Rails Tutorial 翻訳プロジェクトに参加しよー、という誘いの LT があったので、 勢いで参加してしまいました。
ドリンク飲み放題ってのも本当にありがたかったし、お弁当が出たのも嬉しかったです。 Microsoft 様、Engine Yard 様、CodeIQ 様ありがとうございました。
あと、ゆるーい絵のステッカー貰えて嬉しかった。
今までExpress5800/110Gd をいろいろ強化して使っていたのだが、これを更に強化するぐらいなら 新しいの買った方が良い気がしてきたので、 MicroServer に 乗り換えることにした。
Express5800/110Gd 強化版のスペック
MicroServer のスペック
さて、この MicroServer というやつは ここ に「低消費電力のAMD Turion™ II NEO を採用。コンパクトな筐体に加え、PC並みの静音と省電力を実現した、小規模オフィスでのご利用に最適なエントリーサーバーです。」と書いてある。
というわけで消費電力にどれぐらい差が出るのかを ワットメーター付きの電源タップで測ってみた。
Express5800/110Gd
うーん、全く起動してなくて、電源をコンセントに挿しているだけの状態でも 3Wも食うのかぁ。これが待機電力というやつかぁ。
あと、電源を入れているときは Celeron 420 もだいぶ省電力な方だと思うのだが、 それでも常時70Wぐらいは食っている。
MicroServer
というわけで、CPUの性能は約3倍、メモリの量も2倍に増えているが、 消費電力は4割減ぐらいになっている。これは良い。理論上は電気代が月500円ぐらい 安くなるはず。
MicroServer はハードウェアの中身も非常に整理されていて、 コンパクトな割には HDD の換装なども比較的しやすいようになっている。 形はちょっと Next Cube に似ているけど、角が丸いので、あんまり Next cube っぽさは感じない。
静音性は Express5800 とそんなに大きくは変わらない気がする。
というわけで、そんなにパワーを必要としないけど電力消費を抑えたい人には MicroServer は大変良い選択肢だと思います。
OSはDebian(Wheezy)を使ってますが、firmware-linux-nonfreeというパッケージを入れないと、MicroServer の NIC が認識されなかったので、注意すること。
HP ProLiant MicroServer N54L (TurionII NEO N54L 2.2Ghz/2GB/250GB)
背景画像から作り始めたら、案の定死亡フラグで全然間に合わなかった。
当日は島田さんに時間調整などして頂いて何とか発表できました。
いくつか不完全だった場所を直したり、発表中に受けたご指摘を 反映させたりした資料を公開しておきます。
あと、OCamlプレゼン用背景画像も作りましたので、 もし使いたい方がいらっしゃればご自由にどうぞ。
日記というよりは年記というべき状態になっているヤバイ。Twitter, Facebook, Githubの大勝利ってことよね...
去年の目標の振り返り。
去年は本業が忙し過ぎたり、札幌Ruby会議2012の準備が忙しかったり、娘にいろいろ経験させるのに忙しかったりで、ほとんどそれ以外のことに手を出せなかった。
その他。
今年の目標。
今年はOCamlの4.0系が出たり、opamというかなりイケてるパッケージ管理システムが出て来たりしたので、 OCamlの開発環境を作り直した。
typerex というのも今年出たので気になってるんだけど、私の環境では3.12.1ではビルドが通らないし、 4.00.1だとビルドは通るけど、emacsとサーバーが通信始めると例外が起きるので、様子見中。
というわけで、相変わらずtuaregなのであった。
前提とする環境は以下。
手順は大まかには以下のようになる。
ってな感じ。では、上から順番に行きます。
あまり説明の必要ないですね。
$ time brew install -v ocaml ==> Installing opam dependency: objective-caml ==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/objective-caml-4.00.1.lion.bottle.tar.gz Already downloaded: /Users/tmaeda/Library/Caches/Homebrew/objective-caml-4.00.1.lion.bottle.tar.gz ==> Pouring objective-caml-4.00.1.lion.bottle.tar.gz /usr/bin/tar xf /Users/tmaeda/Library/Caches/Homebrew/objective-caml-4.00.1.lion.bottle.tar.gz ==> Finishing up ln -s ../Cellar/objective-caml/4.00.1/bin/ocamlyacc ocamlyacc (中略) ==> Summary /usr/local/Cellar/objective-caml/4.00.1: 1187 files, 209M real 0m12.321s user 0m6.090s sys 0m4.586s $ which ocaml /usr/local/bin/ocaml $ ocaml -version The OCaml toplevel, version 4.00.1
早いですね。バイナリで配布されてるようだ。
opam ってのはパッケージ管理システムで、OCaml用の 各種ライブラリやソフトウェアをお手軽に取得・ビルドできるってものなんだけど、 なんとOCamlのコンパイラ自身もこいつでインストールすることができる。 Rubyに喩えるなら gem と rvm の機能を opam ひとつで担っている感じ。
brew で入れるので、これもあまり説明の必要がないですね。
$ time brew install -v opam ==> Downloading https://github.com/OCamlPro/opam/tarball/0.7.7 Already downloaded: /Users/tmaeda/Library/Caches/Homebrew/opam-0.7.7.tgz /usr/bin/tar xf /Users/tmaeda/Library/Caches/Homebrew/opam-0.7.7.tgz ==> ./configure --prefix=/usr/local/Cellar/opam/0.7.7 ./configure --prefix=/usr/local/Cellar/opam/0.7.7 (中略) ==> make install make install mkdir -p /usr/local/Cellar/opam/0.7.7/bin /usr/bin/make opam-install opam-mk-repo-install install _obuild/opam/opam.asm install _obuild/opam-mk-repo/opam-mk-repo.asm mkdir -p /usr/local/Cellar/opam/0.7.7/share/man/man1 && cp doc/man/* /usr/local/Cellar/opam/0.7.7/share/man/man1 ==> Cleaning ==> Caveats OPAM uses ~/.opam by default to install packages, so you need to initialize the package database first by running (as a normal user): $ opam init and add the following line to ~/.profile to initialize the environment: $ eval `opam config -env` Documentation and tutorials are available at http://opam.ocamlpro.com ==> Finishing up ln -s ../Cellar/opam/0.7.7/bin/opam-mk-repo opam-mk-repo ln -s ../Cellar/opam/0.7.7/bin/opam opam ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam.1 opam.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-upload.1 opam-upload.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-upgrade.1 opam-upgrade.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-update.1 opam-update.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-switch.1 opam-switch.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-search.1 opam-search.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-remove.1 opam-remove.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-remote.1 opam-remote.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-reinstall.1 opam-reinstall.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-pin.1 opam-pin.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-list.1 opam-list.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-install.1 opam-install.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-init.1 opam-init.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-info.1 opam-info.1 ln -s ../../../Cellar/opam/0.7.7/share/man/man1/opam-config.1 opam-config.1 ln -s ../../Cellar/opam/0.7.7 opam ln -s ../Cellar/opam/0.7.7 opam ==> Summary /usr/local/Cellar/opam/0.7.7: 22 files, 7.3M, built in 40 seconds real 0m40.329s user 0m23.127s sys 0m8.502s $ which opam /usr/local/bin/opam $ opam --version opam version 0.7.7 Copyright (C) 2012 OCamlPro - INRIA This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $
うまく行くと上記のように40秒ぐらいで終わる(on MacBook Air 11inch 2012)が、 たまに
tar xfz ocamlgraph-1.8.1.tar.gz rm -rf ocamlgraph mv ocamlgraph-1.8.1 ocamlgraph 100 232k 100 232k 0 0 35205 0 0:00:06 0:00:06 --:--:-- 48537
のところで止まって、全然先に進まないことがあった。
おそらく次の
tar xfz dose3-3.1.1.tar.gz rm -rf dose mv dose3-3.1.1 dose
っていうやつをダウンロードする際に、ネットワークかサーバーの調子などで うまく行かないことがあるんだと思うので、数分待っても先に進まないようなら、 何度かやり直した方が良いと思う。
あと、opam は現在絶賛開発中で、バージョンが上がると、設定ファイルの フォーマットが変わったり、大きく機能が変更されたりするので、 バージョンアップすると今までの設定ファイルが読み込めなくてうまく 動かなくなったり、blogなどに書いてある方法を試しても その通りに動かなかったりということが現時点ではまだよくあるので、 そういう心構えで使いましょう。
動かなくなっても最悪またゼロからインストールすれば良いよ。
さて、上記のインストールプロセスの最後に出ているように opam init したり、 eval `opam config -env` をshellの設定ファイルに書いたりしないといけない。
$ time opam init Synchronizing with http://opam.ocamlpro.com ... The following actions will be performed: - install base-threads.base - install base-bigarray.base - install base-unix.base 3 to install | 0 to reinstall | 0 to upgrade | 0 to downgrade | 0 to remove =-=-= base-bigarray.base =-=-= Downloading http://opam.ocamlpro.com/archives/base-bigarray.base+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/base-bigarray.base+opam.tar.gz Build commands: ./build.sh Installing base-bigarray.base =-=-= base-threads.base =-=-= Downloading http://opam.ocamlpro.com/archives/base-threads.base+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/base-threads.base+opam.tar.gz Build commands: ./build.sh Installing base-threads.base =-=-= base-unix.base =-=-= Downloading http://opam.ocamlpro.com/archives/base-unix.base+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/base-unix.base+opam.tar.gz Build commands: ./build.sh Installing base-unix.base real 0m11.399s user 0m1.681s sys 0m1.862s $
これでホームディレクトリの下に ~/.opam ってディレクトリができて、 ここに各種必要なファイルなどが生成される。
opam では $ opam switch でコンパイラーを切り替えられるんだけど、 切り替える度に手で eval `opam config -env` しろって言われて、 それを自動化するための スクリプト もあるんだけど、たぶんこの記事を必要とするOCaml入門な人は そんなに頻繁にコンパイラ切り替えたりしないと思うので、スクリプト使うなり 手でやるなり好きにしてください。
これから opam を使っていろいろパッケージを入れたくなるんだけど、 その前にちょっとひと手間。
ocamlcやocamloptに、 -annot とか -bin-annot というオプションをつけてコンパイルすると コンパイル結果のバイナリの他に.annotや.cmtという拡張子がついたファイルが 生成されるようになる。このファイルにはソースコードの解析結果(変数や関数の型とか)が 書かれているので、これと ocamlspot というソフトを利用して、 型や関数の定義場所に一瞬で飛んで行けるようになり、非常にソースコードを読むのが 楽になる。
しかし、opam 経由でコンパイルされる際には -annot や -bin-annot 付きで コンパイルされるとは限らないので、 opam 経由でインストールするライブラリは そのままでは ocamlspot でサクサク読めない。
で、ocamlspot 作者のcamlspotterさんが、 環境変数 OCAML_ANNOT=1 を指定しておけば、常に-annot -bin-annot付きで コンパイルされるようになるパッチを公開してくれているので、 このパッチを当てたコンパイラを opam で入れ直す。
$ opam switch -list --- Installed compilers --- * system --- Available compilers --- 3.12.1 3.12.1 (3.12.1+mirage-unix-direct) 3.12.1 (3.12.1+mirage-xen) 4.00.0 4.00.0 (4.00.0+debug-runtime) 4.00.0 (4.00.0+fp) 4.00.0 (4.00.0+jocaml) 4.00.0 (4.00.0+raspberrypi) 4.00.1 4.00.1 (4.00.1+annot) 4.00.1 (4.00.1+raspberrypi) 4.00.1 (4.00.1+short-types) ~ 4.00.1 (system)
4.00.1+annot ってのが見えますね。ではこれをインストールしましょう。 インストールする前に、環境変数 OCAML_ANNOT=1 を設定しておくと、 ocaml の標準ライブラリがビルドされる際にも -annot 付きで コンパイルされるので、嬉しい事がある、、、はず。
$ export OCAML_ANNOT=1
$ time opam switch 4.00.1+annot
(中略)
To update $PATH, $MANPATH, $OCAML_TOPLEVEL_PATH, $CAML_LD_LIBRARY_PATH; you can now run:
$ eval `opam config -env`
real 38m14.371s
user 36m7.670s
sys 0m59.686s
だいぶ時間かかりますねー。
これ以降、opam でいろいろなパッケージを入れていきますが、 引き続き $ export OCAML_ANNOT=1 な環境で実行していき、 .annot や .cmt が生成される状態でインストールしていきます。
まずは .annot とか .cmt を適切な場所に入れてくれる spotinstall というツール。
$ time opam install spotinstall The following actions will be performed: - install ocamlfind.1.3.3 - install omake.0.9.8.6-0.rc1 - install spotlib.2.0.1 - install spotinstall.1.0.0 4 to install | 0 to reinstall | 0 to upgrade | 0 to downgrade | 0 to remove Do you want to continue ? [Y/n] y =-=-= ocamlfind.1.3.3 =-=-= The archive for ocamlfind.1.3.3 is in the local cache. Extracting /Users/tmaeda/.opam/archives/ocamlfind.1.3.3+opam.tar.gz Build commands: ./configure -bindir /Users/tmaeda/.opam/4.00.1+annot/bin -sitelib /Users/tmaeda/.opam/4.00.1+annot/lib -mandir /Users/tmaeda/.opam/4.00.1+annot/man -config /Users/tmaeda/.opam/4.00.1+annot/lib/findlib.conf make all make opt make install Installing ocamlfind.1.3.3 =-=-= omake.0.9.8.6-0.rc1 =-=-= The archive for omake.0.9.8.6-0.rc1 is in the local cache. Extracting /Users/tmaeda/.opam/archives/omake.0.9.8.6-0.rc1+opam.tar.gz Applying opam.patch Build commands: make bootstrap PREFIX=/Users/tmaeda/.opam/4.00.1+annot make all PREFIX=/Users/tmaeda/.opam/4.00.1+annot make install PREFIX=/Users/tmaeda/.opam/4.00.1+annot Installing omake.0.9.8.6-0.rc1 =-=-= spotlib.2.0.1 =-=-= The archive for spotlib.2.0.1 is in the local cache. Extracting /Users/tmaeda/.opam/archives/spotlib.2.0.1+opam.tar.gz Build commands: ocaml setup.ml -configure --prefix /Users/tmaeda/.opam/4.00.1+annot ocaml setup.ml -build ocaml setup.ml -install Installing spotlib.2.0.1 =-=-= spotinstall.1.0.0 =-=-= The archive for spotinstall.1.0.0 is in the local cache. Extracting /Users/tmaeda/.opam/archives/spotinstall.1.0.0+opam.tar.gz Build commands: ocaml setup.ml -configure --prefix /Users/tmaeda/.opam/4.00.1+annot ocaml setup.ml -build ocaml setup.ml -install Installing spotinstall.1.0.0 real 8m2.623s user 9m54.915s sys 0m40.680s $ which spotinstall /Users/tmaeda/.opam/4.00.1+annot/bin/spotinstall
次に、.annot や .cmt を利用して変数や関数の定義場所を 探してくれる ocamlspot というツール。
$ time opam install ocamlspot The following actions will be performed: - install ocamlspot.4.00.0.2.0.1 1 to install | 0 to reinstall | 0 to upgrade | 0 to downgrade | 0 to remove =-=-= ocamlspot.4.00.0.2.0.1 =-=-= The archive for ocamlspot.4.00.0.2.0.1 is in the local cache. Extracting /Users/tmaeda/.opam/archives/ocamlspot.4.00.0.2.0.1+opam.tar.gz Build commands: make all opt install BINDIR=/Users/tmaeda/.opam/4.00.1+annot/bin EMACSDIR=/Users/tmaeda/.opam/4.00.1+annot/lib/ocamlspot PREFIX=/Users/tmaeda/.opam/4.00.1+annot cp ocamlspot.vim /Users/tmaeda/.opam/4.00.1+annot/lib/ocamlspot Installing ocamlspot.4.00.0.2.0.1 real 1m3.277s user 0m59.064s sys 0m3.035s $ which ocamlspot /Users/tmaeda/.opam/4.00.1+annot/bin/ocamlspot
次に utop。より強力なtop levelといったところでしょうか。 rubyで言う所の pry。
$ time opam install utop The following actions will be performed: - install camomile.0.8.3 - install react.0.9.4 - install lwt.2.4.2 - install zed.1.2 - install lambda-term.1.2 - install utop.1.2.1 6 to install | 0 to reinstall | 0 to upgrade | 0 to downgrade | 0 to remove Do you want to continue ? [Y/n] y =-=-= camomile.0.8.3 =-=-= Downloading http://opam.ocamlpro.com/archives/camomile.0.8.3+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/camomile.0.8.3+opam.tar.gz Build commands: ./configure --prefix /Users/tmaeda/.opam/4.00.1+annot --sbindir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/sbin --libexecdir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/libexec --sysconfdir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/etc --sharedstatedir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/com --localstatedir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/var --libdir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/lib --includedir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/include --datarootdir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/share make make install Installing camomile.0.8.3 =-=-= react.0.9.4 =-=-= Downloading http://opam.ocamlpro.com/archives/react.0.9.4+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/react.0.9.4+opam.tar.gz Build commands: ocaml setup.ml -configure --prefix /Users/tmaeda/.opam/4.00.1+annot ocaml setup.ml -build ocaml setup.ml -install Installing react.0.9.4 =-=-= lwt.2.4.2 =-=-= Downloading http://opam.ocamlpro.com/archives/lwt.2.4.2+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/lwt.2.4.2+opam.tar.gz Build commands: ./configure --disable-libev --enable-react --disable-ssl --enable-unix --enable-extra --enable-preemptive make build make install Installing lwt.2.4.2 =-=-= zed.1.2 =-=-= Downloading http://opam.ocamlpro.com/archives/zed.1.2+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/zed.1.2+opam.tar.gz Build commands: ocaml setup.ml -configure --prefix /Users/tmaeda/.opam/4.00.1+annot ocaml setup.ml -build ocaml setup.ml -install Installing zed.1.2 =-=-= lambda-term.1.2 =-=-= Downloading http://opam.ocamlpro.com/archives/lambda-term.1.2+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/lambda-term.1.2+opam.tar.gz Build commands: ocaml setup.ml -configure --prefix /Users/tmaeda/.opam/4.00.1+annot ocaml setup.ml -build ocaml setup.ml -install Installing lambda-term.1.2 =-=-= utop.1.2.1 =-=-= Downloading http://opam.ocamlpro.com/archives/utop.1.2.1+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/utop.1.2.1+opam.tar.gz Build commands: ocaml setup.ml -configure --prefix /Users/tmaeda/.opam/4.00.1+annot ocaml setup.ml -build ocaml setup.ml -install Installing utop.1.2.1 real 6m21.436s user 3m53.935s sys 0m25.729s $
後はコマンドラインから以下のように起動する。
$ utop
すると、こんな感じになる。派手!

しかもインクリメンタルサーチでモジュール名や関数名の 補完ができる。一応、emacs用のインターフェースもあるらしいけど、 うまく動かせたことがない。
次に batteries。rubyで言うところの ActiveSupport。 便利なモジュールや関数がいっぱい定義されてます。
$ time opam install utop The following actions will be performed: - install camomile.0.8.3 - install react.0.9.4 - install lwt.2.4.2 - install zed.1.2 - install lambda-term.1.2 - install utop.1.2.1 6 to install | 0 to reinstall | 0 to upgrade | 0 to downgrade | 0 to remove Do you want to continue ? [Y/n] y =-=-= camomile.0.8.3 =-=-= Downloading http://opam.ocamlpro.com/archives/camomile.0.8.3+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/camomile.0.8.3+opam.tar.gz Build commands: ./configure --prefix /Users/tmaeda/.opam/4.00.1+annot --sbindir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/sbin --libexecdir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/libexec --sysconfdir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/etc --sharedstatedir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/com --localstatedir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/var --libdir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/lib --includedir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/include --datarootdir=/Users/tmaeda/.opam/4.00.1+annot/lib/camomile/share make make install Installing camomile.0.8.3 =-=-= react.0.9.4 =-=-= Downloading http://opam.ocamlpro.com/archives/react.0.9.4+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/react.0.9.4+opam.tar.gz Build commands: ocaml setup.ml -configure --prefix /Users/tmaeda/.opam/4.00.1+annot ocaml setup.ml -build ocaml setup.ml -install Installing react.0.9.4 =-=-= lwt.2.4.2 =-=-= Downloading http://opam.ocamlpro.com/archives/lwt.2.4.2+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/lwt.2.4.2+opam.tar.gz Build commands: ./configure --disable-libev --enable-react --disable-ssl --enable-unix --enable-extra --enable-preemptive make build make install Installing lwt.2.4.2 =-=-= zed.1.2 =-=-= Downloading http://opam.ocamlpro.com/archives/zed.1.2+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/zed.1.2+opam.tar.gz Build commands: ocaml setup.ml -configure --prefix /Users/tmaeda/.opam/4.00.1+annot ocaml setup.ml -build ocaml setup.ml -install Installing zed.1.2 =-=-= lambda-term.1.2 =-=-= Downloading http://opam.ocamlpro.com/archives/lambda-term.1.2+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/lambda-term.1.2+opam.tar.gz Build commands: ocaml setup.ml -configure --prefix /Users/tmaeda/.opam/4.00.1+annot ocaml setup.ml -build ocaml setup.ml -install Installing lambda-term.1.2 =-=-= utop.1.2.1 =-=-= Downloading http://opam.ocamlpro.com/archives/utop.1.2.1+opam.tar.gz ... Extracting /Users/tmaeda/.opam/archives/utop.1.2.1+opam.tar.gz Build commands: ocaml setup.ml -configure --prefix /Users/tmaeda/.opam/4.00.1+annot ocaml setup.ml -build ocaml setup.ml -install Installing utop.1.2.1 real 6m21.436s user 3m53.935s sys 0m25.729s $
で、~/.ocamlinit に以下を記述(~/.opam/4.00.1+annot/lib/batteries/ocamlinitの中身をコピペ)。
let interactive = !Sys.interactive;;
Sys.interactive := false;; (*Pretend to be in non-interactive mode*)
#use "topfind";;
Sys.interactive := interactive;; (*Return to regular interactive mode*)
Toploop.use_silently
Format.err_formatter (Filename.concat (Findlib.package_directory
"batteries") "battop.ml");;
で、ocaml を起動すると、以下のように電池(batteries)のアスキーアート付きの toplevel(対話シェル)に変わる。

.ocamlinitに書いた #use "topfind" によって、topfind が 利用可能になる。 topfind ってのは、ocaml のライブラリを探す ocamlfind というソフトウェアの機能の一つで、 toplevelからも ocamlfind の機能を利用できるようにするものらしい。 Ruby で言う所の require 'rubygems' みたいなものか?
で、その後の Toploop ほにゃららってので、ocaml 標準の toplevel 内で、 引数で指定した battop.ml ってのを実行する。 battop.ml ってのは batteries が定義している toplevel の機能で、この中で #require "batteries" などが行われるために、batteries の各種モジュールが 利用可能になったり、電池のAAが出たりするらしい。
この状態で utop を起動すると、さっきよりも更にいろいろ出る。

batteries によっていろいろなモジュールや関数が定義されるので、 以下のような範囲を指定したloopなども簡単にかける。
$ (1--100) |> Enum.reduce (+);; - : int = 5050
ちなみに、型はこんな感じ。
$ (--);;
- : int -> int -> int BatEnum.t = <fun>
$ (|>);;
- : 'a -> ('a -> 'b) -> 'b = <fun>
他にもモナドとか無限リストとかリスト内包表記とかいろいろある。
Getting Started とか New apis とか api document 参照。
名前からおわかりのように、OCaml で実装された make。 依存関係の解決が非常に強力らしい。
あと、omake -P すると omake がずっと起動しっぱなしになって、 ファイルの変更を検知すると、自動的に再びビルドが走るという機能が 付いている。 ruby でいうところの、 guard とか watchr みたいな機能が rake に内蔵されてる感じ。この機能を使えば、自分でビルドしなくても 勝手にビルドが走るので、自分の書いたコードの型チェックを自動で 走らせながら、非常に高速に開発できる。
で、インストールですが、上記の spotinstall を入れたときに、 自動的に入ったので、自分で入れる必要は無し。
tuareg は以下から取得。
<URL:https://forge.ocamlcore.org/frs/?group_id=43>
$ tar xfvz tuareg-2.0.6.tar.gz $ cd tuareg-2.0.6
中身を眺めるとMakefileがあるので、make を叩いてみるが、
Makefile:97: *** missing separator. Stop.
とエラーする。なんだろう?makeのバージョンの違いとか? よくわからないけど、不要な箇所なので、
$(DIST_NAME).tar.gz $(DIST_NAME).tar: $(DIST_FILES) mkdir -p $(DIST_NAME) for f in $(DIST_FILES); do $(LN) $$f $(DIST_NAME); done echo '(define-package "tuareg" "$(VERSION)" "$(DESCRIPTION)" ' "'"'$(REQUIREMENTS))' > $(DIST_NAME)/tuareg-pkg.el tar acvf $@ $(DIST_NAME) $(RM) -rf $(DIST_NAME)
をまるっと削って、make する。
$ make EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs
/Applications/Emacs.app/Contents/MacOS/Emacs -batch -f batch-byte-compile tuareg.el
Wrote /Users/tmaeda/rpm/SOURCES/tuareg-2.0.6/tuareg.elc
/Applications/Emacs.app/Contents/MacOS/Emacs -batch -f batch-byte-compile ocamldebug.el
Wrote /Users/tmaeda/rpm/SOURCES/tuareg-2.0.6/ocamldebug.elc
echo "\
;;; tuareg-site-file.el --- Automatically extracted autoloads.\n\
;;; Code:\n\
(add-to-list 'load-path\n\
(or (file-name-directory load-file-name) (car load-path)))\n\
" >tuareg-site-file.el
/Applications/Emacs.app/Contents/MacOS/Emacs --batch --eval '(setq generated-autoload-file "'`pwd`'/tuareg-site-file.el")' -f batch-update-autoloads "."
Generating autoloads for ocamldebug.el...
Generating autoloads for ocamldebug.el...done
Generating autoloads for tuareg-pkg.el...
Generating autoloads for tuareg-pkg.el...done
Generating autoloads for tuareg.el...
Generating autoloads for tuareg.el...done
Saving file /Users/tmaeda/rpm/SOURCES/tuareg-2.0.6/tuareg-site-file.el...
Wrote /Users/tmaeda/rpm/SOURCES/tuareg-2.0.6/tuareg-site-file.el
(No changes need to be saved)
install ターゲットが定義されてないみたいなので、手でコピーする。 コピー先は自分がelispのインストール場所として使っている場所 (load-pathが通ってる場所)に読み替えてください。
$ cp -p *.el{,c} ~/.emacs.d/site-lisp/
次に ocamlspot.el。これは opam install ocamlspot したときに、 /Users/tmaeda/.opam/4.00.1+annot/build/ocamlspot.4.00.0.2.0.1/ocamlspot.el などに入っているので、後は M-x auto-install-from-buffer などで入れるだけ。
で、以下のような設定を ~/.emacs.d/init.el などに書きましょう。 私はinit-loaderを入れているので、 ~/.emacs.d/inits/50-ocaml.el に書いてますけども。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; tuareg-mode
(setq auto-mode-alist (cons '("\\.ml[iylp]?$" . tuareg-mode) auto-mode-alist))
(autoload 'tuareg-mode "tuareg" "Major mode for editing Caml code" t)
(require 'tuareg)
(autoload 'camldebug "camldebug" "Run the Caml debugger" t)
(setenv "PATH"
(concat '"/Users/tmaeda/.opam/4.00.1+annot/bin:" (getenv "PATH")))
;(setq ocamlspot-command "/usr/local/bin/ocamlspot")
(setq ocamlspot-command "/Users/tmaeda/.opam/4.00.1+annot/bin/ocamlspot")
(setq tuareg-interactive-program "/Users/tmaeda/.opam/4.00.1+annot/bin/ocaml")
(setq omake-program-path "/Users/tmaeda/.opam/4.00.1+annot/bin/omake")
;(setq omake-program-arguments "-P -w --verbose")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; flymake
;; cf) http://d.hatena.ne.jp/osiire/20120613
(require 'flymake)
(push '("File \"\\(.*\\)\", line \\([0-9]+\\), characters \\([0-9]+\\)--?\\([0-9]+\\):\\(.*\\)" 1 2 3 5) flymake-err-line-patterns)
(push '("\\.ml\\'" flymake-ocaml-init) flymake-allowed-file-name-masks)
(defun flymake-ocaml-init ()
(list "/bin/bash" (list "-c" (format "%s -s 2>&1 | tr -d \"\\n\" | sed -Ee 's/[[:space:]]+/ /g'" omake-program-path))))
(custom-set-faces
'(flymake-errline ((((class color)) (:background "LightYellow" :underline "OrangeRed"))))
'(flymake-warnline ((((class color)) (:background "LightBlue2" :underline "Yellow")))))
;; cf) http://d.hatena.ne.jp/khiker/20070720/emacs_flymake
(defun credmp/flymake-display-err-minibuf ()
"Displays the error/warning for the current line in the minibuffer"
(interactive)
(let* ((line-no (flymake-current-line-no))
(line-err-info-list (nth 0 (flymake-find-err-info flymake-err-info line-no)))
(count (length line-err-info-list))
)
(while (> count 0)
(when line-err-info-list
(let* ((file (flymake-ler-file (nth (1- count) line-err-info-list)))
(full-file (flymake-ler-full-file (nth (1- count) line-err-info-list)))
(text (flymake-ler-text (nth (1- count) line-err-info-list)))
(line (flymake-ler-line (nth (1- count) line-err-info-list))))
(message "[%s] %s" line text)
)
)
(setq count (1- count)))))
(defadvice flymake-goto-prev-error (after flymake-goto-prev-error-display-message activate)
(credmp/flymake-display-err-minibuf))
(defadvice flymake-goto-next-error (after flymake-goto-next-error-display-message activate)
(credmp/flymake-display-err-minibuf))
(require 'ocamlspot)
(defun run-ocamlspot-type ()
(if (eq major-mode 'tuareg-mode)
(ocamlspot-type)
)
)
(defvar ocamlspot-type-timer nil)
(defun toggle-ocamlspot-type-timer ()
(interactive)
(if ocamlspot-type-timer
(progn
(anything-new-timer 'ocamlspot-type-timer nil)
(message "auto ocamlspot-type disabled")
)
(anything-new-timer 'ocamlspot-type-timer
(run-with-idle-timer 0.5 t 'run-ocamlspot-type)
)
(message "auto ocamlspot-type enabled")
)
)
(defun tuareg-mode-init ()
;; indentation rules
(setq tuareg-lazy-= t)
(setq tuareg-lazy-paren t)
(setq tuareg-in-indent 0)
(setq tuareg-electric-indent nil)
(setq tuareg-leading-star-in-doc t)
(setq tuareg-with-indent 0)
; (setq tuareg-library-path "/usr/local/lib/ocaml/")
(setq tuareg-library-path "/Users/tmaeda/.opam/4.00.1+annot/lib")
;; turn on auto-fill minor mode
(auto-fill-mode 1)
;; Sym-Lock customization only
;; turn off special face under mouse
(if (featurep 'sym-lock)
(setq sym-lock-mouse-face-enabled nil))
;; ocamlspot and other keys
(local-set-key "\C-c;" 'ocamlspot-query)
(local-set-key "\C-c:" 'ocamlspot-query-interface)
(local-set-key "\C-c'" 'ocamlspot-query-uses)
; (local-set-key "\C-c\C-t" 'ocamlspot-type)
(local-set-key "\C-c\C-i" 'ocamlspot-xtype)
(local-set-key "\C-c\C-y" 'ocamlspot-type-and-copy)
(local-set-key "\C-cx" 'ocamlspot-expand)
(local-set-key "\C-c\C-u" 'ocamlspot-use)
(local-set-key "\C-ct" 'caml-types-show-type)
(local-set-key "\C-cp" 'ocamlspot-pop-jump-stack)
(local-set-key "\C-c\C-t" 'toggle-ocamlspot-type-timer)
(flymake-mode-on)
)
(add-hook 'tuareg-mode-hook 'tuareg-mode-init)
(setq which-func-modes (append which-func-modes '(tuareg-mode)))
;; You can also change overlay colors as follows:
; (set-face-background 'ocamlspot-spot-face "#660000")
; (set-face-background 'ocamlspot-tree-face "#006600")
で、上記を M-x eval-region するなり、Emacsを再起動するなりしましょう。
では簡単なソースコードでomakeを試してみましょう。 まずはソースコードを入れるディレクトリを作成します。
$ mkdir omaketest
次に、そのディレクトリの中に omake の設定ファイルを生成します。
$ cd omaketest $ omake --install
これで、OMakefile と OMakeroot というファイルが出来上がります。
OMakeroot というのは、プロジェクトのトップディレクトリを 表すものなので、トップディレクトリにしか置かないファイルです。
OMakefile がビルドのルールを定義するものです。 では、エディタで OMakefile を開いて、以下を記述しましょう。
.PHONY: all run clean
USE_OCAMLFIND = true
FILES[] =
foo # ビルド対象のソースコードの名前(拡張子不要)
PROGRAM = foo # ビルドした結果できるバイナリのファイル名
OCAMLPACKS[] += batteries # リンクするライブラリ
#OCAMLFLAGS += -thread
OCAMLFLAGS += -annot -bin-annot # コンパイラに渡すフラグで ocamlspot を使えるように
.DEFAULT: run # デフォルトのターゲットは run だよ
all: $(OCamlProgram $(PROGRAM), $(FILES))
clean:
rm -f *~ $(PROGRAM) *.opt *.cmi *.cmx *.o *.omc *.cmt *.annot
run: all # run は all に依存するよ
./$(PROGRAM)
次に、簡単なソースコードを書きましょう。 foo.ml という名前で batteries のサンプルコードを打ち込んでみましょう。
open Batteries_uni let main () = (1--999) (* the enum that counts from 1 to 999 *) |> Enum.filter (fun i -> i mod 3 = 0 || i mod 5 = 0) |> Enum.reduce (+) (* add all remaining values together *) |> Int.print stdout let () = main ()
これで omake を実行してビルドしてみましょう。
$ omake *** omake: reading OMakefiles *** omake: finished reading OMakefiles (0.01 sec) - build . <run> + ./foo 233168[================================================================================================================== ] 00019 / 0*** omake: done (0.67 sec, 0/1 scans, 4/6 rules, 5/90 digests)
というように、ビルドされて、実際に実行まで行われて 結果の 233168 というのが表示されています。
また、 omake -P を実行すると、ファイルの更新を検知して ずっとビルドを繰り返してくれますので、いちいち自分で
という作業をしなくて済みます。素晴らしい!
例えば、上記のソースコードの (1--999) を (1--99) に書き換えて保存すると
$ omake -P *** omake: reading OMakefiles *** omake: finished reading OMakefiles (0.01 sec) - build . <run> + ./foo 233168[================================================================================================================== ] 00019 / 0*** omake: done (0.67 sec, 0/1 scans, 4/6 rules, 5/99 digests) *** omake: polling for filesystem changes *** omake: file foo.ml changed *** omake: the project is currently locked. *** omake: the project was last locked by macair.localhost.localdomain:39969. *** omake: waiting for project lock: .*** omake: another OMake process have modified the build DB, restarting *** omake: reading OMakefiles *** omake: finished reading OMakefiles (0.01 sec) - build . <run> + ./foo 2318[================================================================================================================== ] 00019 / 000*** omake: done (33.19 sec, 1/1 scans, 4/6 rules, 5/99 digests) *** omake: polling for filesystem changes
ってな感じで、ファイルシステムをポーリングして、 更新を検知し、自動的にビルドしなおして、実行結果の 2318 が出力 されていることがわかりますね。
lock がうんちゃらというエラーみたいのが 出てるけど、もしかして flymake の omake とぶつかってるんだろうか...
シンタックスカラーリング、Emacs内でREPLの起動、今自分が書いている ソースコードの一部をREPLに送って評価したりできる。
既に何かの .ml ファイルを開いていて、 tuareg-mode になっている のであれば、C-c C-s すれば、toplevel のコマンドを指定しろと 言われるので、デフォルトのまま(/Users/tmaeda/.opam/4.00.1+annot/bin/ocaml) で Enter。

すると、こんな風に Emacs の中に toplevel が起動する。

例えば、今書いているコードの Int.print の型ってなんだっけ? ってわからなくなったときは、 Int.print をリージョンで選択した 状態で、C-c C-r すると、その部分が toplevel に送られて評価され、 型が 'a BatInnerIO.output -> int -> unit = <fun> だとわかる。

他にも定型句を入力する機能とかあるけど、詳しくは メニュー見るなり、C-h m や C-h b で調べるなり、 ソース読むなりしましょう。

といっても、定型句は yasnippet とか auto-complete とかでやるよね。
omake -P があれば要らないような気もするが...エラーにすぐに 飛んで行けるのは便利。
例えば、上記のコードの
|> Int.print stdout
の行を削除してみましょう。 すると、 flymake で omake が走るようにしてあるので、 omake でビルドされて、エラーの行が赤くなるので、M-N などで すぐにエラーに飛んで行けると同時に、ミニバッファにエラーの 内容が表示されます。

omake-mode が動くのが一番幸せな気がするが、私の環境ではなぜか Emacs に omake の結果が表示されたりされなかったりで、 うまく動かなかったので、断念中。いずれ時間かけて調べてみたい。
では、ocamlspotを試してみましょう。ocamlspotを利用するには、 コンパイルで生成されたcmi/cma/cmxaと一緒にcmt/cmtiなどが 存在していないといけないらしい。
しかし当然普通のMakefileなりビルドスクリプトなりは ocamlspot のことを考慮してはいないので、cmt/cmtiなどは インストールされない。 そのインストールをほぼ自動化してくれるのが同じく camlspotterさんが作ってくれているspotinstallというツール。
以下のように実行すると、とりあえずさっき入れたocamlの 標準ライブラリ用の cmt/cmti などが適切な場所にコピーされる。
$ spotinstall -v ocaml found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/arg.cmi found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/arg.cmx found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/arg.p.cmx found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/arith_flags.cmx found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/arith_status.cmi found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/arith_status.cmx found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/array.cmi found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/array.cmx found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/array.p.cmx found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/arrayLabels.cmi found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/arrayLabels.cmx found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/arrayLabels.p.cmx (中略) found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Filters/Camlp4TrashRemover.cmi found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Filters/Camlp4TrashRemover.cmo found /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Filters/Camlp4TrashRemover.cmx Copied ./.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Top/Rprint.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Top Copied ./.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Top/Rprint.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Top Copied ./.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Top/Rprint.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Top Copied ./.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Top/Top.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Top (中略) Copied ./.opam/4.00.1+annot/build/ocaml/_build/camlp4/Camlp4Filters/Camlp4TrashRemover.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Filters Copied ./.opam/4.00.1+annot/build/ocaml/_build/camlp4/Camlp4Filters/Camlp4TrashRemover.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Filters Copied ./.opam/4.00.1+annot/build/ocaml/_build/camlp4/Camlp4Filters/Camlp4TrashRemover.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/camlp4/Camlp4Filters No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/outcometree.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/cmx_format.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/parsetree.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/topdirs.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/topdirs.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/topmain.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/expunge.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/topstart.cmo No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/asttypes.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/toploop.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/genprintval.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/cmo_format.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/topstart.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/annot.cmi No spot/spit/cmt/cmti found for /Users/tmaeda/.opam/4.00.1+annot/lib/ocaml/compiler-libs/trace.cmi
あと、他にもいくつかライブラリっぽいものを入れたので、それらも同じくspotinstallする。 なんか、ocaml のトップディレクトリに居る状態じゃないと、うまくファイルを見つけられない???ので、一応 cd してから実行。
$ cd ~/.opam/4.00.1+annot/ $ spotinstall -v spotlib found /Users/tmaeda/.opam/4.00.1+annot/lib/spotlib/spotlib.cmi found /Users/tmaeda/.opam/4.00.1+annot/lib/spotlib/spotlib.cmo found /Users/tmaeda/.opam/4.00.1+annot/lib/spotlib/spotlib.cmx Copied ./build/spotlib.2.0.1/lib/spotlib.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/spotlib Copied ./build/spotlib.2.0.1/lib/spotlib.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/spotlib Copied ./build/spotlib.2.0.1/lib/spotlib.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/spotlib
同様に、 batteries にも。
$ spotinstall -v batteries found /Users/tmaeda/.opam/4.00.1+annot/lib/batteries/batArg.cmi found /Users/tmaeda/.opam/4.00.1+annot/lib/batteries/batArg.cmx found /Users/tmaeda/.opam/4.00.1+annot/lib/batteries/batArray.cmi (中略) found /Users/tmaeda/.opam/4.00.1+annot/lib/batteries/batVect.cmi found /Users/tmaeda/.opam/4.00.1+annot/lib/batteries/batVect.cmx found /Users/tmaeda/.opam/4.00.1+annot/lib/batteries/pa_comprehension.cmo found /Users/tmaeda/.opam/4.00.1+annot/lib/batteries/pa_llist.cmo Copied ./build/batteries.1.5.0/_build/src/batArg.cmti to /Users/tmaeda/.opam/4.00.1+annot/lib/batteries Copied ./build/batteries.1.5.0/_build/src/batArg.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/batteries Copied ./build/batteries.1.5.0/_build/src/batArray.cmti to /Users/tmaeda/.opam/4.00.1+annot/lib/batteries (中略) Copied ./build/batteries.1.5.0/_build/src/batVect.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/batteries Copied ./build/batteries.1.5.0/_build/src/syntax/pa_llist/pa_llist.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/batteries Copied ./build/batteries.1.5.0/_build/src/syntax/pa_comprehension/pa_comprehension.cmt to /Users/tmaeda/.opam/4.00.1+annot/lib/batteries
この状態で、例えば ~/.opam/4.00.1+annot/build/spotinstall.1.0.0/spotinstall.ml を開くと こんな感じになる。

さて、OCaml のソースを読み解く上で非常に難しいのが、
という点です。
上記のソースでも例えば
imp_ None & fun ocamlfind_path ->
ignore & shell_command "ocamlfind printconf destdir" & function
| (`Out, `Read line) ->
begin match !ocamlfind_path with
| Some _ -> failwith "ocamlfind printconf destdir prints more than one line"
というコードがあり、関数もいろいろわからないことだらけですが、 それに加えて & とか ! とかも出現し、これが一体どういう意味なのか初学者には 非常に難しいです。他の言語から来た人にとって、 & はビット演算ですし、!は否定(not)の意味に見えてしまいます。
では、ocamlspot の威力を見てみましょう。上記の & の上にカーソルを持って行って、

Emacs で C-c : すると...

ってな感じで、インターフェース定義のところに飛んで行けて、あー、 Haskell の $ と同じなのね、とかわかる。
同様に、! の上にカーソルを持って行って、

Emacs で C-c : すると...

というように、同じくインターフェース定義のところに飛んで行けます。
OCamlは.mliというインターフェースファイルと、.ml という実装ファイルが 分かれており、関数の説明のコメントなどは 大抵 .mli の方に書かれるので、 まずは C-c : でインターフェースを見て、それでもよくわからなければ、 C-c ; で実装を見る、って感じでソースを読んで行くと良いです。
移動先で C-c p すると、元居た場所に戻れます。
他にも C-c C-t すると、カーソルの合わせてある箇所の型が自動的に ミニバッファに表示されるように先程 init.el に書いたので、

というように shell_command 関数の型がミニバッファに表示される。 もう一度、C-c C-t すると、自動型表示モードを off にします。 これらはソースコードを読むときの重要な助けになります。
これは ocaml 入れると一緒に入ってくる。
SmalltalkのBrowserみたいなやつ。メソッド名で検索できたり、型で検索できたりする。

一応、EditorとかREPLもあるんだけど、 tuareg があったら不要ですね...
以下の本の最後にも解説がある。
長々とお読み頂きありがとうございました。