Carrotに静的型付けを実装していくうちに、あれを表現するには代数データ型が必要だ、あれにはシノニム、あれには型クラスなりインターフェースなりが必要、そうするとimplementsだかinstanceだかみたいなのも必要になるし、って結局どんどんHaskellに近づいていってて、冷静になって考えると僕が欲しかったのはこういうんじゃないんだと気づいた。
頭の整理のために要件をまとめてみる。
(済) 関数が基本
主な理由 -> Real World Objects // Speaker Deck
(済) シンタックス
文字列を書いているんじゃなくてデータを書いているような気分になるS式が好き。 構文は少なければ少ないほどいい。理想は関数定義と関数適用のみ。 マクロはそんなに好きじゃないんだけどユーザに開かれている仕組みなので許容範囲。
(済) 遅延評価でデフォルトでカリー化される
MirandaとかHaskellとかの特徴。これは単純に便利なので欲しい。 カリー化すると可変長引数関数が作れなくなる代わりに、S式の括弧を減らせるという利点もある。
(未着手) そもそもデータ型を定義したくない
Clojureでは型を作らない文化があって、既存の抽象データ型をそのまま使うスタイルが主流。 これは割と好き。
(途中) 静的型付けと型推論
これは一つ前の要件と関係する。なんでもMapで表現して、かつ動的型付けだと関数が正しい型の実引数に適用されることを期待するダックタイピングになってしまう。実行前にコードを舐めてあきらかに変な関数適用がないかを見つけてほしい。
動的型付けの言語を使うときに、よくドキュメント代わりにML風に関数の型をドックストリングとかコメントに書く。どうせ書くなら型の文法を仕様に組み込んで型チェッカにもこの情報を使ってほしい。
(未着手) 総称関数とマルチメソッド
総称関数なりインターフェースなりがあって、組み込み型の階層がしっかり設計されていると、あまり型を意識せずに式を書ける。
Haskellみたいにインターフェースとパターンマッチを別々の仕組みにしてもいいんだけど、マルチメソッドがあればある程度まで両方の役目を果たせるからマルチメソッドが欲しい。ただ型を定義しないスタイルだからCLOSみたいにクラスでディスパッチするんじゃなくて他の仕組みが必要。Clojureみたいにディスパッチに使う方法を指定できるのもいいかも。
呼ばれるメソッドを静的に決定できたらなおよし。
(悩み中) 純粋関数しか書けない
純粋関数しか書けないようにするか、純粋関数と非純粋手続きの区別をはっきりさせて両立できるようにするか悩み中。Timed I/Oとかっつって折衷案の実験中。
コンセプトを少なくする
最近のオブジェクト指向で嫌いなのがコンセプトが多いこと。クラス、抽象クラス、インターフェース、トレイト、継承、Mixin、オブジェクト等々。最初はオブジェクトとメッセージしかないっていうシンプルさが売りだったのになんでこんなことになってしまったんだ。
これはHaskellみたいな型セントリックな関数型言語でも同じで、代数的データ型(型とコンストラクタ)、シノニム、型クラスとインスタンス等々。型に重きを置くとこうなるのは必然なのかもしれない。
SchemeとかSmalltalkくらいのシンプルさが欲しい。
以上
TypedRacketに遅延評価とカリー化とマルチメソッドをくっつけたら割と近いと思う。
と、こんな方向でまたちょこちょこCarrotをいじって行こうと思います。Carrotが趣味になりつつある。