自前の関数型電卓のパースが間に合わなかったのと、先週の.NETラボ勉強会で「関数型言語の本質とは?」にうまく答えられなかったので、それっぽい言語を考えてみる。
うーん。私自身は関数型言語自体を扱っている期間が短いので、先駆者の言葉を借りれば「関数プログラミング」から「式が簡略化できる」ことと、「型システム入門」から「型が決まる/推論可能である」ことに尽きる…と思うのだけど、じゃあ、オブジェクト指向型言語との違いは?というと、なんだろう。
実は、「オブジェクト指向型言語は内部に状態を持つ、対して関数型言語は内部に状態を持たない」というのは正しいのだけど、オブジェクト指向型言語に根拠があるので、これは「ごまかし」である(ごまかしと分かっていて言うんだけど)。でも、状態を持たない(あるいは持てないように作る)ので、パラレル化がしやすいし、ドメイン駆動設計による分散に対象になる(内部にアトムを持たないので)。
で、懇親会で話したように、
- 「オブジェクト指向による関数型言語」
- 「関数型指向によるオブジェクト指向型言語」
ってのも考えられるわけで、どちらの排他的なものにはならない。特に F# の場合は、内部でクラスが作れるしオブジェクト指向的な .NET Framework も使えるわけで、そのあたりは良しなにハイブリット的に作れる。加えていれば、LISP は LISP なので、関数型言語に入れると怒る人がいるかもしれない。
以前、Ruby で後付メソッドが作れる、JavaScript のプロトタイププログラミングを知った頃に、すべてのメソッドのプロパティが virtual であればよかろうというのを思いついたことがある。今でいえば、C# の dynamic なんだけど、F# の型推論と組みあわせると、もっと静的言語に近い形で実現できないか?と妄想してみる。
view = name = "masuda tomoaki" address = "tokyo" age = 46 button.click = db.submit (name,address,age) name is TextBox address is ComboBox age is TextBoxOnlyNumber button is Button .submit t = insert into Person values ( t.name, t.address, t.age )
F# も C# もそうだけど、関数定義やクラス定義は前置参照が基本になる。これはコンパイル時点にワンパスになるような工夫でもあるし、コンパイル時の時間短縮でもある。しかし、Javascript や ruby のように後付けでメソッドが作れる場合は(先付のメソッドとは完全に同じではないにせよ)実行時にメソッドの存在をチェックすることになる。
が、これを型推論をフルに使って「あらゆるオブジェクトのメソッド/プロパティを後付けできる」と定義してしまう。先の例だと view で、やりたいことは「name, address, age の3項目があってデータベースに登録する」」ということなので、それを先に書く。これらがどういうものかは後で書く。
「name is TextBox」ってのは、正確に書くと「name that is TextBox」になる。詳細を that で補完していく英語の構文になる。先に適当なことを書いて、後から追記する方式です。
更に言うと、この .submit 部分はあとから上書きができて
.submit t = insert into Person values ( t.name, t.address, t.age ) .submit t = fs = open "person.txt" fs.write t.name t.address t.age
のように後ろに二番目の .submit をつけると、これが採用される。普通は前置メソッドが優先されるが、後付け言語 post では、後から定義したほうを採用するので、後ろの .submit が使える。
当然、null オブジェクトのメソッドはどうなるか?とか問題があるけど、Objective-C の nil のように、無視する。こうなると、obj.?method のような変な記号を使わなくていいので、タイピングが楽になる…ハズ。
もうちょっと適当に考えると、
main v1 = (10,20) v2 = (30,40) ans = v1 + v2 printfn ans main.(+) x y = ( x[0] + y[0], x[1] + y[1] ) main.(+) x y = ( x.0 + y.0, x.1 + y.1 ) main.(+) x y = this.left = x.left + y.left this.right = x.right + y.right .left (x,y) = x .right (x.y) = y .left (x,y,z) = x .middle (x,y,z) = y .right (x,y,z) = z
こんな風にベクトルの計算を考える。型推論を使えば、2つの .right メソッドは容易に区別がつくので、間違わない。むろん、プログラミングしているときは間違えそうな気もするけど。