Differences between revisions 8 and 9
| Deletions are marked like this. | Additions are marked like this. |
| Line 17: | Line 17: |
| 他の人の入門講座ではなく、'''私自身が'''入門してゆく過程を書こうという唯我独尊なコーナーです。 | 他の人の入門講座ではなく、'''私自身が'''入門してゆく過程を書こうという唯我独尊なコーナーです。OCaml のコードと同等な Python コードを出来るだけ書いています。 |
| Line 88: | Line 88: |
|
(関係ないですが、Pythonで無理やり定数を作るには、property を使用してこんな感じに出来るといえば出来る {{{#!python class hoge: def __init__(self): self.x_ = 10 @property def x(self): return self.x_ h = hoge() print h.x}}} ) |
|
| Line 101: | Line 90: |
| C++のtemplateみたいに、ひとつの関数を別のクラスのインスタンスに適用できるみたいです。これを使ってみる予定です。 |
クラスを使えば、C++のtemplateみたいに、ひとつの関数を別のクラスのインスタンスに適用できます。 {{{#!ocaml class hoge = object method get_val = 10 end;; class fuga = object method get_val = 20 end;; let h = new hoge;; let f = new fuga;;}}} としておきます。そして、関数を一つ作っておきます。 {{{#!ocaml let func x = x#get_val;;}}} この関数は引数 {{{x}}} のメソッド {{{get_val}}} を呼び出すだけです。この関数には、{{{hoge}}} のインスタンスでも、{{{fuga}}} のインスタンスでも渡せます。 {{{#!ocaml func h;; (* 結果は 10 *) func f;; (* 結果は 20 *)}}} C++ (やD言語) のtemplateと同じように使えるわけです。C# や Java の generics と違って、インターフェイスを用いずとも、引数のメソッドを呼べるようになっています。 では、このときの {{{x}}} の型、というか、{{{func}}} の型はどうなっているのかな? と見てみると… {{{ val func : < get_val : 'a; .. > -> 'a = <fun>}}} だそうです。これは、 * {{{func}}} は「{{{get_val}}} というメソッド (型は {{{'a}}}) を持つ任意の型」を引数にとり、{{{'a}}} 型の値を返す関数 ってことのようです。{{{'a}}} ってのは、単相型ってやつかな? 上みたいに {{{h}}} を引数として渡した場合、{{{h#get_val}}} が {{{int}}} 型なので、{{{'a}}} は {{{int}}} になるみたいです。 うへぇ。型推論すげえなあ。 |
OCaml
オブジェクト指向のML系関数型言語OCaml (Objective Caml) 関連。
最近、Microsoft が .NET Framework に F# として移植 (?) したことで、もしかして火がつくか?! いよいよ、コンパイラ型関数型言語の時代が来るのか?!
Objective Caml 公式サイト
OCamlチュートリアル 有用なチュートリアル
Wiki.OCaml.JP OCamlのWiki
OCaml (私が) 入門
他の人の入門講座ではなく、私自身が入門してゆく過程を書こうという唯我独尊なコーナーです。OCaml のコードと同等な Python コードを出来るだけ書いています。
クラスを書こう
関数よりも先にクラスを書いてみます。
1 class hoge =
2 object
3 method get_val = 10
4 end;;
必ず 10 を返すメソッド get_val を持つクラス hoge を作ったわけです。Python的に書けば
1 class hoge:
2 def get_val(self):
3 return 10
ですね。メソッド get_val の型は、型推論により自動的に int となります。
クラスのインスタンスは
1 let h = new hoge;;
で作ります。Pythonの h = hoge() に相当します。ここでも、h の型は、型推論により hoge になります。メソッド get_val を呼ぶには # を使用して
1 h#get_val
です。Pythonなどの h.get_val() ですね。
クラスは関数と同じく引数を取れるようです。C++などのコンストラクタに相当することが出来るみたいです。
1 class hoge init_val =
2 object
3 method get_val = init_val + 10
4 end;;
5 let h = new hoge 20;;
とすることで
1 h#get_val
が 20 + 10 で 30 になるんですね。
ここでは、init_val が init_val + 10 という式で使われていることから、init_val の型は int と型推論されます。式の中で使わず、
1 class hoge init_val =
2 object
3 method get_val = init_val
4 end;;
とすると、init_val の型を推論できないといって、エラーになってしまいました。そこで、明示的に型を指定してやります。
1 class hoge (init_val : int) =
2 object
3 method get_val = init_val
4 end;;
これで正しく、
1 let h = new hoge 20;;
2 h#get_val;;
で 20 が表示されます。
インスタンス変数
OCaml は関数型言語ですが、変数やインスタンス変数もあるようです。これを使ってみる予定です。
まずは、変更できないインスタンス変数です。関数型言語なのでこちらがデフォルトです。
1 class hoge =
2 object
3 val x = 10
4 method get_x = x
5 end;;
Pythonには定数がないのですが、こんな感じ
1 class hoge:
2 def __init__(self):
3 self.x = 10
4 def get_x(self):
5 return self.x
ジェネリックプログラミング
クラスを使えば、C++のtemplateみたいに、ひとつの関数を別のクラスのインスタンスに適用できます。
1 class hoge =
2 object
3 method get_val = 10
4 end;;
5 class fuga =
6 object
7 method get_val = 20
8 end;;
9 let h = new hoge;;
10 let f = new fuga;;
としておきます。そして、関数を一つ作っておきます。
1 let func x = x#get_val;;
この関数は引数 x のメソッド get_val を呼び出すだけです。この関数には、hoge のインスタンスでも、fuga のインスタンスでも渡せます。
1 func h;; (* 結果は 10 *)
2 func f;; (* 結果は 20 *)
C++ (やD言語) のtemplateと同じように使えるわけです。C# や Java の generics と違って、インターフェイスを用いずとも、引数のメソッドを呼べるようになっています。
では、このときの x の型、というか、func の型はどうなっているのかな? と見てみると…
val func : < get_val : 'a; .. > -> 'a = <fun>
だそうです。これは、
func は「get_val というメソッド (型は 'a) を持つ任意の型」を引数にとり、'a 型の値を返す関数
ってことのようです。'a ってのは、単相型ってやつかな? 上みたいに h を引数として渡した場合、h#get_val が int 型なので、'a は int になるみたいです。
うへぇ。型推論すげえなあ。
継承
となると、あとは継承かな。
