関数型初心者にこそおすすめしたい言語 "OCaml"

cedretaber氏(以下、cedretaber):「関数型初心者にこそおすすめしたい言語 "OCaml"」ということで、またOCamlの話だということになってしまうんですが。

自己紹介、cedretaberと申します。

「ドワンゴから来ました」って言うと、「ドワンゴにはOCamlをやるやつしかいないのか」って思われてしまうかもしれないんですけど(笑)。

(会場笑)

ふだんはScalaとかを書いてて、Scalaけっこう好きです。あとは趣味でOCamlを書いています。

今回は初心者向けです。初心者向けなので、あんまり難しいことは言いません。難しいことを言ってしまった人たちは、ちょっと悔い改めていただきたいんですが。

(会場笑)

関数型言語の話をします。

最近よく聞くようになりましたよね。っていうかこんな勉強会に来てるぐらいだから、多少は興味ある人ばかりだと信じています。で、新しい言語の中にも「関数型の性質を取り入れた」って言ってるのが少なくないですね。例えばRustとか、TypeScriptとかがそんな感じです。

この間、社内のランチで「RustはML系かどうか」っていう議論がちょっとあったんですけども、私はわかりませんでした。詳しい人教えてください。

で、ですね。ほかにもコーディング作法とか設計とかで、「関数型の考えを使うといいよね」とか、もうちょっとぶっちゃけた話を言うと「オブジェクト指向って間違ってるよね」みたいな話をする連中もいるんですが(笑)。

(会場笑)

まぁそんなことを言われていますと。オブジェクト指向が間違っているかどうかはちょっと置いておいて、「関数型これだけはやっているんだから、まぁちょっと勉強しておこうか」っていう方々も多いと思うんですよ。かつ、今まで関数型を触ったことがない人ですね。

そういう人には、OCamlをおすすめします。OCamlをやりましょう。OCamlです!

(会場笑)

OCamlがどんな言語かといいますと、フランスで開発された言語ですね。インリアって読むのかな? ちょっと読み方、私は知らないんですけども。フランスのNIIみたいなやつ、っていうかNIIがフランスのこれをもとにして作られたのかな。MLっていう言語の一族になります。

MLは何かといいますと、「自動定理証明」っていう難しいことのために作られた言語ですね。

これはまったくの余談になるんですけども、「純粋関数型はテストがしやすい」っていう話がさっき出ていたんですけども、私はちょっとこのあたり素人だからよくわからないんですけど、「テストなんていい加減なものを書かなくても、証明しちゃえばいいんじゃないのか」という話を……。

(会場笑)

今日、社内の勉強会で聞きました。私はそんなことぜんぜん思ってません、テスト大好きです(笑)。

MLにはいろんな方言があるんですよ。SMLとかOCamlとか、SML#とか。Hindley-Milner式の型システムを持っていて、あとはヘッドでのパターンマッチ……これを属に「ドラゴンパターンマッチ」と言うらしいんですけども、そんなことを言っている人は私は2人しか知りません(笑)。

(会場笑)

あとガベージコレクションとか、正格評価、カリー化みたいな、いわゆるML系の特徴っていうのはもう最初の段階で出揃っていたんですね。

その中に「Caml」っていう方言があったらしいんですよ。それがどんな言語かはぜんぜん知らないんですけど。そのCamlに対して、オブジェクト指向の機能を付け加えたのがOCamlになります。つまり、関数型とオブジェクト指向のハイブリッド言語ということですね。なんかScalaっぽいですよね。

なんですけども、今回はオブジェクト指向の機能については一切取り扱いません。なんでかというと、OCamlを使ってる人たち、誰に聞いても「あんなもの使わないよ」って言ってたからです(笑)。

(会場笑)

Scalaがちゃんとオブジェクト指向と関数型をきっちり混ぜているあたりに比べると、ちょっとおもしろいところですね。

OCamlをおすすめする理由

「じゃあなんでお前はそんなにOCamlを推すんだよ」っていう話になると思うのですが、いくつか理由があります。

1つはこれ、「情報量」です。初心者が何かを勉強するときに、情報量って大事じゃないですか。ここで大事っていうのは、少ないともちろん困るわけですけども、多すぎてもいいわけではありません。

(会場笑)

逆に言うと、いい記事は多い。例えばOCamlの公式サイトの日本語チュートリアルです。これ日本語に訳されてるんですけど、とても丁寧でわかりやすいです。英語版のほうが量が多いので、英語版のほうを見てほしいんですが。

あと日本語の書籍でもいいのがあります。『プログラミングの基礎』、浅井(健一)先生の本ですね。

プログラミングの基礎 ((Computer Science Library))

これは実はプログラミング初心者、関数型とかOCamlじゃない、プログラミング初心者向けに書かれたOCamlの本なんですよ。これはOCamlを使って地下鉄のネットワークの最短経路を探索する、みたいなことをやってる本なんですけども。非常にわかりやすくていい本なので、読んでみてください。

あと『プログラミング in OCaml』は、OCamlをやる人、つまりこの場にいる全員なんですけども。

(会場笑)

この方々は全員読まなきゃいけない本ですね。

プログラミング in OCaml 〜関数型プログラミングの基礎からGUI構築まで〜

電子書籍で手に入るので買ってください。間違えて『プログラミング言語の基礎概念』は買わないようにしてください(笑)。

(会場笑)

プログラミング言語の基礎概念 ((ライブラリ情報学コア・テキスト))

この本、すいません「間違えて」とか書いてあるんですけど、すごくいい本です。めちゃくちゃいい本なので読んでほしいんですけども、ちょっと初心者にはおすすめできないかな、という本ですね。わかる人にだけ言うと、TAPL本の少し簡単版みたいな感じ。私はTAPL本よりちょっと難しいと感じたんですけども。

シンプルである

もう1つのおすすめする理由が「シンプルであること」です。「シンプル」と「イージー」の対立、みたいな話がよく言われていますが、OCamlはとてもシンプルです。基本的な機能はとても少ないですし、変数とか関数、制御式、バリアント、レコードぐらいですかね。これらを組み合わせるだけで、大抵のアプリケーションが作れます。

……ウソです。ファンクターとか知ってないとたぶん、実用的なアプリケーションはちょっと難しいんですけども。まぁ学ぶ上ではこれだけで十分と。で、少ない機能で高い表現力を持っています。かつ、それ以上の機能を「あまり」要求しないです。

例えばですよ、初心者がHaskellに手を出すことを考えてください。じゃあ「Hello World」を書こうかな、って思うことを考えてください。「何? まずIOモナドを使って?」とかなるわけですよ。これは死ですね。

ほかにもScalaをやるじゃないですか。じゃあまず初心者が最初に手を出すのは何でしょう、そうFizzBuzzですね。じゃあFizzBuzzをどうやってやるか、「えーと、コンパイラで……」。

(会場笑)

これは死んでしまいますよね(笑)。これに比べるとOCamlは、初心者の方が使っても……初心者というのはこの場合プログラミング初心者ではなくて、いわゆるALGOL系の言語を知ってらっしゃる方のことを言ってるんですけども。そういう方が使っても問題なくプログラムが書ける中身になっています、と。いいですね?

現在の主流言語との距離

最後に「距離」です。最後になってよくわかんない単語が出てきたな、と思われると思うんですけど、これは現在の主流言語との距離を意味します。

C言語、Java、Python、Rubyといった、いわゆるさっき言ったALGOL系。ALGOL系っていう言葉はどのぐらい世に広まってるかわからないんですけども、ふつうに使われる言語だと思ってください。それと比べての距離のことですね。

ML系の言語っていうのはちょっと、ALGOL系と比べると変わった文法をしていて。具体的には関数の呼び出し周りですかね。これが違うんですよね、やっぱりOCamlは。ですが、その違うところがいい。まったく同じではないから壁があるけれども、乗り越えやすい、みたいな感じなんですよ。

かつOCamlはループとか副作用を許すっていう、ちょっと一般的な言語を知っている人に優しい作りになっています。つまり、適度な距離を保っているわけですね。

(スライド表示のみ:「初心者にLispをやらせたりするのは虐待なのでNG」)

……はい。

(会場笑)

(笑)。

OCamlを学ぶ

では、OCamlを学んでいきましょう、と。ちなみに私「オキャムル」って言ってるんですけど、「オーキャメル」のほうが発音が正しかったりするんですかね? なんか、教えて詳しい人。

学習については、さっき述べたサイトとかでやってくださいとしか言えないので。ここでは関数型先般の特徴的なところを、少しだけ触れていこうと思います。

第一級関数については触れません。なぜかというと、最近の言語を使ってる人なら誰でも知ってるよね、って思うからです。

まず、式指向です。

これはC言語のコードリストですね。だいたいやってることはわかると思って……ゼロで割ったらエラーになるのがイヤだから、そのときだけゼロを返す、っていう雑なことをやっています。

これは見てわかるとおり、中で「return」っていうキーワードを使って値を返しています。かつ上のほうの「int ret = 0;」っていうのも、まずretっていう変数を宣言して、それに0を代入する、みたいな意味になります。

ここでは、文っていうのが何個か出てくるわけですね。もっと言うと「if」も文で、これは値を返さないので、例えばこのifの結果をなにかに代入する、みたいなことはできないわけですね。

ですが、OCamlでは例えばifっていうのは、式なわけです。なのでifを評価した結果が最後に返ってくる、という意味論になります。ごめんなさいね、ここもっといい感じの説明を考えろって思ってたんですけれども、ついにできなかったので。ちょっと流させていただきます。

次、immutableです。ごめんなさい、式指向のことはもう忘れてください。

(会場笑)

immutableって何かっていうと、私は2種類あると思っていて。1つは「変数に1回代入したらもう二度と代入しない」っていう意味。もう1つが「オブジェクトが1回なにか値が入ったら、もう二度とその値が変わらない」っていう意味。たぶん広い意味で見れば同じなんですけど、ここで言うのは「オブジェクトの不変性」を意味します。

例えばこれはたぶんJavaBeansとかいうやつだと思うんですけども、「user」っていうのを作って、名前と年齢を入れるっていう処理を行っています。このあと最後の行で、もう1回年齢を入れ直してるんですね。このときにuserっていう、作った変数の中身が変わってしまっていますね。

こういうコードを書いて何がつらいかというと、例えばどこかで期待すべき値ではないものが見られたときに、じゃあその値はどこで入れられたのかっていうのを、今までの通ってきたコードを全部追って見ていかなきゃいけないと。これはつらいですね。

一方でOCamlでそのコードを書くとどうなるかというと、こんな感じになります。

ここで見ていただきたいのは、「user2」っていうのは「user1」のフィールドを全部コピーして、かつ「age」だけを別のものに上書きする、みたいな意味のコードになるんですよ。このあたり、「全部コピーするのって計算行多くない?」とか、そういう話もあるんですけども。「実際はポインターだからコピーはしてなくて~」みたいな、ぐだぐだとした説明をするのがイヤなのでちょっと飛ばすんですが。

こんな感じで、1回作ったものを変更しないっていう性質があります。この性質自体については、ほかの言語……ぱっと出てこないんですけど、例えばRubyだったら変数をフリーズして動かないようにする、みたいなのがけっこう広く認められたデザインパターンだったりして、使われているのですけども。多くの関数型言語では、そういう性質が最初から入っていますと。そういったものを自然に学ぶことができます。

バリアントとパターンマッチ

次です、「バリアント」です。バリアントって何でしょうか。これはC言語で書かれた判別共用体です。

私はC言語をちゃんと書いたことがないので、こういうコードもそんなに書いたことはないのですけども。何がやりたいかっていうと、この「type」っていうのでその入ってる値が何かを判別して正しい値を呼び出す、みたいな感じですね。

これは何がつらいかは、まぁ言わなくてもわかると思うのですが。「このtype読み出し忘れたら死ぬよね」とか「間違った値にアクセスしちゃったら突然の死だよね」とか、そういうところですね。ただしC言語はそういうことができてしまいますし、あるいはそれを防ぐ手段とかもありません。別にC言語を批判したいわけではないっていうことを、ちょっとご了承ください(笑)。

OCaml等で使われているバリアントってどういうものかといいますと、こんな感じで定義できるんですけども。

これはこの「information」っていうtypeが、「purchase」か「refound」かのどちらかしか取らない、みたいなことを宣言しており。かつ、それぞれの中にTupleで値を持たせることができるということになります。

これを使うことで、型レベルでその型の中身が何かというのを正しく判断することができ、間違ったアクセスとかを防ぐことができます。

これはこの次の「パターンマッチ」とつながるんですけども、例えばこういうコードを、JavaScriptを書かれる方であればけっこう書くと思います。

stateとactionを取って、actionのtypeによって処理を振り分けて、actionの中身に応じてstateを更新する、みたいな感じですね。

これは実はTypeScriptとかでけっこう型安全に書けてしまうのですけども、例えば「actionのtypeを振り分け忘れたら突然の死を迎える」ですとか、「actionのデータの中身を別のものにアクセスしてしまったらその場でコケる」とか、いろいろつらいことがあるわけですね。TypeScriptだとそのへん、つらくないようにできてしまうので。あんまりこれ、例としてよくなかったなぁとは思うんですけども。

(会場笑)

まぁTypeScriptが関数型言語なので、やっぱり関数型言語は正義なんですよ(笑)。これをOCamlで書くとこうなります。

さっき言ったバリアント機能とパターンマッチを利用して、かつパターンマッチの分解などを用いて、きれいにstateを更新することができます。

もう1つ言うとこのstateというのはimmutableなデータなので、作られているのは新しいstateということになりますね。ということは、例えば過去のstateに間違えてアクセスしてしまっても、そこでデータの不整合が起こってることはない、というようなことが保証できるわけです。

「再帰」。

再帰はまぁいいですよね、みなさん再帰関数書きますので。

OCamlを使う

……はい。みたいな感じで、ざーっとOCamlというか、関数型言語の機能をなめたんですけども。OCamlを使いましょう。「opam」というツールがあるので、コンパイラのバージョンとかライブラリとか、いい感じに入れられます。

プロジェクト管理には「dune」っていうツール……「デューン」って読み方、合ってるんですかね? これを使うとプロジェクトも作れます、と。このへんは、最近のモダンな言語のように使えます。コマンドラインツールとかGUIを作れます。

でもちょっと待ってほしいんですよね。最近の開発でコマンドラインツール作っても、あんまり楽しくないじゃないですか。かといって、リッチなUIを備えたGUIツール。これはちょっとライブラリ選ぶのに面倒くさそう、って思うじゃないですか。

残念ですよね、OCamlいい言語なのに簡単に使えない。ブラウザ上で動かせたらなぁ……って思いますよね? 思うんですよ。

(会場笑)

「BuckleScript」があります!

(会場笑)

BuckleScriptです。

Facebookが開発しているAltJSなんですが、OCamlコンパイラを改造して作られてるんですよ。つまりOCamlです。JSにコンパイルされてブラウザ上で動くんです。ブラウザ上で動くっていうことは、つまりどこでも動くっていうことです。「30億のデバイスで動くJava」どころじゃないですよ、もう。

(会場笑)

最近、ブラウザが乗ってないような端末はないですからね。しかもこいつは、JSとの連携が簡単なように作られてるんですよ。たぶんみなさん、JavaScriptは書いたことがあるでしょうし。エンジニアとして生きていく上でJavaScriptを書かされることってけっこう多いと思うので、嫌々でもなかなか覚えてると思うんですけども。

JavaScriptってそういうふうにいろんな人が使うので、とってもとっても便利なライブラリが多いわけですね。そういったものをなんと、OCamlから使うことができるんですよ。

しかももう1ついいのが、npmを使って環境が構築できるわけですね。npm、まぁyarnでもいいんですけど、それらを使って依存性管理ができるんですよ。opamとかduneとかいいんですけども、やっぱり慣れたツールを使いたいなという場合に、npmとかに寄せていくのは悪くないと思います。npmってぶっちゃけバイナリを配布するためのツールなので、これで正しいと思ってもいるんです。で、JSのライブラリが利用できますと。

いいんですけども、でもフロントエンドを書くんだったらフロントエンドのフレームワークを使いたいよね、ってなるわけですよね。例えば今どき、生のJSだけで画面を作りたくはないと。やっぱり何らかのライブラリは使いたい、となるわけですよ。……なるわけですよ。

(会場笑)

「ReasonReact」がございます!

(会場笑)

これ何かといいますと、ReactのReasonバインディングです。

「Reasonって何?」っていう人は、今すぐググってください。簡単にいうとOCamlみたいなもんです。

(会場笑)

実質Reactなので、Reactの知識がそのまま使えるんですよ。React使ったことある方はわかると思うんですけども、関数型言語とReactの相性ってめちゃくちゃいいんですよ。React使ったことある人が関数型言語を一緒に使ってるかどうかは、ちょっとアレなので。やっぱりみなさん、今からReasonReactを入れて使ってみてください。

BuckleScriptでOCamlを学ぶことで、関数型の基礎が身につきます。それが身についたら、今度はReasonReactを使って画面を作ることで、関数型の応用が身につくんですよ。素晴らしいと思いませんか? こんなに学習環境の整ったOCaml、使わないわけにはいかないですよね?(笑)。

ということで、この3言語をよろしくお願いします。以上です。

(会場拍手)

司会者:よければ質疑応答をぜひ。

cedretaber:あ、はい。じゃあ何か質問とかありましたらお答えします。……おぉ、みなさんもうOCamlは完璧に理解できたということで。

(会場笑)

OCamlが理解できたわけじゃないですね、「OCamlを学ぶ意義」は理解できて、明日からでももうOCamlを勉強してみたいと思っていらっしゃる、ということで間違いないですね?

(会場笑)

ありがとうございました。

(会場拍手)