Tech Days 2009のT3-310 F#入門で使用したサンプルコードを公開させていただきます。このサンプルには、以下のものが含まれています。
ご利用はZIPアーカイブに含まれるReadme.txtに添ってお願いいたします。
To:セッションにご参加された方達へ 関数型言語を知っていらっしゃった方には、申し訳ございません。参加された方のほとんどが関数型言語を使っていないということで、説明させていただいた内容が基本的なものになってしまいました。この中で私が強調したのが、関数型言語における肝とは「式(Expression)」であるというものです。このためにF#のコンパイラは、「1.ToString()」と「(1).ToString()」が異なる意味に解釈すると説明しました。前者は、リテラルなので何のメソッドも持っていないとF#コンパイラが解釈した結果としてエラーになりました。後者は「(1)」という式をF#コンパイラが解釈した結果、Int32オブジェクトを式が返した結果としてToStringメソッドを呼び出すことができました。 それからカリー化に関して、式は入れ子になった関数として表現でき、結果として引数は左に収束し、式は右に収束するという説明をさせていただきました。このことを説明するために「let add1 a b = a + b」は、「let add2 a = fun b -> a + b」という例をお見せしました。この2つの関数をF#コンパイラは、「int -> int -> int」と表現します。この表現を正しく説明するとすると、int型の引数を取りint型を返す関数(int -> int)を戻し、戻した関数にint型の引数を渡すと、int型の戻り値を返すとなります。「->」が、F#におけるラムダ演算子になります。このため「add1 10」という関数呼び出しが、「val it : (int -> int) = <fun:clo@2>」という関数を戻したのです。また、引数が左に収束し、式は右に収束するという仕組みを理解すると、add2関数を「add2 10 2」と記述することが可能になります。これを正確に記述するとすれば、「(add2 10) 2」ということです。括弧内の式が関数を戻し、戻した関数に引数として2を与えているのです。このような特徴が、カリー化によってもたらされていることになります。
いげた太さんのコメントにもあるように、「1.ToString()」というのは、少し適切じゃないかも知れません。ここで説明したかったのは、()で囲むと式になっているという点です。そしてセッションでお話しましたが、式は必ず値を返す必要があるということです。数学で学んだ式とは、方程式や計算式になると思いますが、これらの式は必ず値(変数を含んでいても)を返しますよね。これが式の1つとして関数があると説明した理由です。従って、何も値を返さないということは、有り得ません。このために空の値として、unit(単一の値)というデータ型が用意されています。「()」という表現が、F#ではunit型になります。
PingBack from http://www.anith.com/?p=3743
> 「1.ToString()」と「(1).ToString()」が異なる意味に
関数型言語における肝が式であるというのは賛成ですが、例示としてこれを挙げるのはすこし違うような気がしています。たとえば以下のコードはすべてコンパイル可能な F# コードです。いずれも F# におけるリテラルからメソッドを呼び出したものです。
"1".ToString()
'1'.ToString()
0x1.ToString()
1l.ToString()
ではなぜ「1.ToString()」がダメなのかというと、僕は、現行の F# の仕様ではあいまい性を回避できないからだと推測します。F# では、「1.」を、小数点以下を略記した float 値として解釈します。そのため、「1.ToString()」と書いた場合、それが int の 1 に ".ToString()" がくっついたものなのか、float の 1. に "ToString()" がくっついたものなのか、判断できなくてエラーになるのではないかと。
1. // float = 1.0
1.M // decimal = 1M
字句解析に優先順位でもつければ解決可能なのかなあとも思いつつ。仕様としてそうなのか、それとも決めかねているのか、あるいはバグなのか、ちょっとよくわからないところではあります。
すいません。「判断できなくてエラーになる」というのはちょっとおかしかったかもしれません。「1.ToString()」がダメで「1.M」が OK なのだから、「数値のすぐあとにドットがきた場合、それは即座に float リテラルとして解釈される」というのが正しいのかもしれません。
再度じっくりエラー内容を見てみたら、なんとなくそれっぽい気がしてきました。
error FS0191: This is not a valid numeric literal. Sample formats include 4, 0x4, 0b0100, 4L, 4UL, 4u, 4s, 4us, 4y, 4uy, 4.0, 4.0f, 4N, 4I.
有難うございます。
ふーむ。そんな感じなんでしょうかね。defaultは、intとなっていて、ocamlのような「.+」表記が省かれていましたよね。あー、そう言えば「1.」は、floatと解釈しましたねー。