後付け言語 post を考えてみる

自前の関数型電卓のパースが間に合わなかったのと、先週の.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 メソッドは容易に区別がつくので、間違わない。むろん、プログラミングしているときは間違えそうな気もするけど。

カテゴリー: 開発 パーマリンク