F#でMAL(Make a Lisp)を実装し始めた
MAL with F
少し前に1週間ほど休めたので前々から興味のあったMAL(Make a Lisp)(LISPインタプリタ)を前々から興味のあったF#で実装しはじめました。連休中になんとかStep4までは完了させた(テストでOptionalになっているものは無視)ので、途中で思ったことのメモ。
eshamster/mal · GitHub(F#の実装はすでにあったので、esh-fsharpというフォルダ下で作成)
純粋にF#に関すること
- 参考になったサイト:F#は基本的な文法に関したことを検索してみても、どうにも帯に短し襷に長しな情報(省略されているっぽいそこの情報を知りたいんですが…)や信頼性の低い情報(動かない!動かないよ!)が多く詰まることが多かったです。例えば、たかがクラスの継承に関する情報一つ調べるのに苦労するとは思いませんでした。
- Home | F# for fun and profit:各項目がだいぶ網羅的に書かれていて信頼性も高く参考になりました。
- F# - 七誌の開発Wiki:クラスに関する情報が網羅的に書かれていて参考になりました。
- MSDN:帯に短い情報代表。本当に基本的なことを調べるには役に立ったものの、(F#の)例が少ない、情報が細切れすぎて使いづらいといった感じでした。
- 安定のstackoverflow:襷に長い情報代表。なんだかんだで時々役立ちました。
- 静的型解決について
- 関数型ベースのマルチパラダイム言語、ということでLispに近いイメージで書き始めましたが、大間違いでした。具体的には、型なんて書かなくてもよしなに解釈してくれるんでしょー、まずはパーッと書いて後で合わせればいいよねー、と思っていたらすぐに詰まりました。結局、基本的に型は書いておかないとダメだという結論になりました。それまでは、型推論さんがつけてくれた型が自分のイメージと食い違い、深い階層で型エラー(コンパイルエラー)が頻発していました。
- 久々に静的型言語をがっつり使いましたが、割りと嫌いになれないようです。面倒に思う部分も多々ある一方で、コンパイルさえ通れば大体安心というのはありがたい感覚でした。
気に入ったところ
- match...with素敵
- 大変素敵
- とても柔軟かつ直感的で書きやすいswitch文といったところでしょうか。
- 合わせてOptional Typeもいいですね。
- 使わない引数を"_"とアンダーバー一つで表現できるのは楽でした。
- CLだととりあえず受け取ってから(declare (ignore a b))ですし…。
気に入らなかったところ
- インデントルール微妙
- ネストを深くするのが面倒とか、一行が長くなった時に改行入れるのが毎回おっかなびっくりだとか。この辺りは、Emacsにfsharp-mode入れただけという手抜き環境も悪いので、Visual Studio等で使えば多少意見が変わるかもしれません。そうはいっても、文法解析だけでは一意にインデントが決まらない場合(結構多い)はどうしているのかと思いました。
- 記号の意味を覚えるのが面倒
- オブジェクト指向と関数型と入り交じっていて少し気持ち悪い
- チェインを連ねるときにドットと関数呼び出しが当たり前のように入り混じるので、覚えにくくまた気持ち悪かったです。
- コンパイラ重すぎません…?
- 環境が貧弱なせいもあると思いますがそれにしても…。
- Visual Studio + C#のときは、さほど重い印象はなかったのですが。
大変気に入っている部分と、気持ち悪く感じる部分とがあって、気に入るかどうか評価が難しいという印象です。
MALに関すること
- F# + MALならUbuntuが無難
- 久々にVisual Studioかと意気揚々と2015を入れたのですが、テストでmakeを使うのでまあLinuxですね
- 普段の開発環境がCentOS(@さくらVPS)なので簡単に入れられないか調べていたのですが、どうも面倒くさそうという結論になりました。結局、2年ほど放置していたローカルのUbuntu仮想環境 on VirtualBoxを引っ張りだして使いました。
- 第一級関数:Step2のプラスやマイナスなどの基本的な演算子を環境に登録するパートで思ったこと。
- なんとなく分かったような分からないようなであった「関数が第一級オブジェクト」。静的型言語で実装すると文字通り関数型を用意しろということになるんですね。
- C#で使えるdynamic使えないのだろうか、などと迷走の末にようやくそこに気づきました。MAL用の型システムを作っているんだという意識が希薄だったかなと反省。
- (容易には)動的型を使えないことを不満に思ったりもしましたが、結果的には勉強になりました。
- なんとなく分かったような分からないようなであった「関数が第一級オブジェクト」。静的型言語で実装すると文字通り関数型を用意しろということになるんですね。
- クロージャ:Step4にて
今後
だいぶペースは落ちそうですが、思いの外勉強になるので徐々に進めていく予定です。ただ次のStep5の末尾再帰最適化は再帰で書いてきたものをループに書きなおすということで、関数型っぽさが失われそうで気が進まず手が止まっていますが*2。チュートリアル自体は見ていて、末尾再帰は簡単にループにできるとよく言うけどなるほどなー、と感心はしているのですが。
*1:リードマクロで「便利な文法」を書くと文脈依存性が出てきてしまいますが…
*2:またしばらくCommon Lispで遊びたいのでということもあります