型についてごちゃごちゃと。
なんか、非常に面白い話なので言ってみたかったのですけど、ものすごい人気だったようなので、
ちまちまと考えてみたことを書きます。
結論を先に書くと、TemplateHaskellの型の部分は推論できるところは書かないと短くかけて嬉しいんじゃないかと思います。
構文木をあらわす表示も型推論の逆のことをすれば、簡略化できるよねと。
まずですよ。
プログラムを記述するのは、人間にも、コンピュータにも両方がわかりやすいものがよいです。
っていうことがあります。
最初は全部数字でコンピュータより過ぎた。
で、ニーモニックとアセンブラが生まれた。
そして、コンパイラが生まれ、インタプリタが生まれた。
LISPやforthが生まれ、smalltalkが生まれた。
BNFができて、多種多様な言語が生まれた。
マクロはプログラムを生成する技術だったが、わけがわからないと嫌われた。
オブジェクト指向がたびたびもてはやされるが実行速度は遅い。
さてさてでは、他にどんな案が???
ってことで、c++のテンプレートやら型レベルの計算があったりする。
ってのが現在なのかなぁ???と思います。
で、型って何であるの???
そもそも、型ってのは要するに計算するひとつの単位です。
「人」とか「みかん」とかですな。
その単位を値として扱うってどういうことなんだろうなぁ???
うーん。ってかんじです。
たとえば、1cm/secのcm/secって単位の割り算ですよね。cm/sec=速さ みたいな。
cm*secは長さになる。そんな話しだよなぁっと。
それでプログラム作るってどういうことなのかなぁ???
っと。いうところで思考停止。
型レベルの計算の目的と利点
とりあえず、今現在の型レベルの計算ってなんでやってるのかなぁっと。
現状の人気のある処理系でコンパイル時計算を行える。
元々の目的から離れたつかい方なので
基本的に一から作り出す面白さがある。
また、現在の処理系で動くので実益が得られる。
仕事で使える。
問題
エラーが異常。そもそもの目的に沿ってないのだから仕方ない。
ということで、どうあるべきなんだろう???
まず、現状の人気のある処理系から離れて考えてみるというか、
自分で考えてきたことを書く。
とりあえず、lispのマクロはCのマクロよりいいよね。
問題は括弧だらけ
epp
JavaをS式にしていじって戻せる。
S式とJava混在で余計わけわからない。
Algol文法のマクロ使える言語があればいいじゃないか!
■Dylan
自分で作れそうにない。
■Nemerle
やっぱり自分で作れそうにない。
■Sumi 俺俺言語
実装がごちゃごちゃ。
■Scalaで書いてすっきり。
っていうか、Cleanでインタプリタ的だなぁっと。
俺的にはわかりやすい。けど、LISPのマクロはつまらないってはなし。
template haskellとかと一緒みたいなかんじだもんなぁ。
数値とかまで、定義しなおしたりするところが型レベルプログラミングの面白さ。
数字を定義できる言語ってあったような。Haskelだっけ???Coq???よく覚えていない。
うーむ。まぁ、そういう方向性の言語があったとする。
あったとしてどうなんだ?
っていうと、あったとすると、数字とかはその言語で定義できるわけです。
で、それでアセンブラとかが作れる。
てことで、そういう言語でアセンブラ作って、コンパイラ作ってってできるはずですな。
うーん。。。
コンパイル時に動く言語の単位が型である必要があるのだろうか???
型をいじることが可能。。。うーむ。えーっと。
型ってタグみたいなもんだよなと。
パターンマッチさせるのに使える。型を式の演算子としてしまったらいいんでないの?
演算子は基本的に何かと何かを関連付けるものだ。
1+2*3は2と3を*がつなげている。2*3は*という型だと考えることができる?
1+2*3の型は+だと。1の型は数字なので、実は1っていう数字は数字演算子の下に数値が入っているといいんでないかと。
1+2*3の型は数字なのか、+なのか?っていう問題があるんですけど、どう考えたらいいんだろうなと。
うーん。。。2*3は*型の式だけど、計算結果は6という数値になる。
うーということはいったいどういうこと???
ってところで、落ち着こう。計算式の演算子と型は別。あたりまえだけど。
演算子はやっぱり演算子。型は型だってかんがえたほうがよさそう。
1っていう数値には目に見えないけど数値っていう型と演算子も数値かあるいはプリミティブみたいなのが入ってる。
型付式指向言語においては、すべての物はすべて式で表すことができる。
式は演算子と型、そして2つの値を持つ。
したがって、たとえば1+2*3は以下のような構造となる。
Add:Int{
Primitive:Int{1,VOID},
Mul:Int{
Primitive:Int{2,VOID}
,Primitive:Int{3,VOID}
}
}
S式で書けばこうなる。
(Add Int
(Primitive Int 1)
(Mul Int
(Primitive Int 2)
(Primitive Int 3)))
書式については未定である。
型付式指向言語の計算方法。
とりあえず、型のない状態でパースが行われる。
プリミティブであるものについてのみ型が決定されている。
Add:?{
Primitive:Int{1,VOID},
Mul:?{
Primitive:Int{2,VOID}
,Primitive:Int{3,VOID}
}
}
次に、それぞれの式の型を再帰的に決定する。
単純なパターンマッチである。
Mul:Int{Int,Int}
Add:String{String,Int}
Add:String{String,String}
という定義があればパターンマッチによって型が決定できる。
ってここまで考えてみたもののこれってTemplate Haskell的なものですわな。
演算子、型、そしてノードが複数っというのがいいんだろうなぁと。
でも、長いのは嫌です。
型推論できるところはできることは表示方法にしても同じはず。
なので、できるだけ省略して表示すると結局型のない状態で表示できるはず。
Add{
Primitive{1}
Mul{
Primitive{2}
Primitive{3}
}
}
等と書けば型推論されるようなのがあるといいんではないかと。
じゃあってんで、型推論じゃなくて、結合する演算子が1種類しかないような
場合は、結合する演算子も省略してかけるんではないかなぁっと。
まぁそんな風に思ったのでした。
ってことで、省略できる演算子として、括弧とかがあると。
括弧は型推論的な考え方によって省略できる的な。
また、括弧は逆型推論的なことをすることで省略可能だと言えるんじゃなかろうかと。
ってことで、推論できるように省略をどうするとできるのか?
ってのをプログラムでやるといろいろ面白いんじゃないか?
それっていわゆるショートコーディングの技術???
みたいに思ったりしたのでした。