let 束縛
let 束縛 let Bindings
元ネタ http://msdn.microsoft.com/ja-jp/library/dd233238.aspx
1つの名前を 1 つの単純な値にバインドする式です。
F#
let i = 1
バインド(束縛)を強調すれば、const を付けることになる。
C#
const int i = 1;
式の各行にインデントを設定する必要があります。 F#
let someVeryLongIdentifier = // Note indentation below. 3 * 4 + 5 * 6
C# の場合は、インデントはいらないが、見やすくするために付ける。
C#
let someVeryLongIdentifier = 3 * 4 + 5 * 6;
次のコードに示すように、タプルを指定できます。
F#
let i, j, k = (1, 2, 3)
「バインドをタプルでできる」というよりも、タプルを返す関数から値を取り出す方法と言える。 変数を複数同時に宣言する場合は、こんな感じになる。
C#
const int i = 1, j = 2, k = 3;
タプルから取り出す場合は、こんな感じ。 C#
var t = new Tuple<int, int, int>(1, 2, 3); int i = t.Item1; int j = t.Item2; int k = t.Item3;
let キーワードの先頭の文字と同じ位置になるようにインデントを設定します。
F#
let result = let i, j, k = (1, 2, 3) // Body expression: i + 2*j + 3*k
result への束縛のニュアンスが違うが、普通に値を計算する。
C#
const int i = 1, j = 2, k = 3; const int result = i + 2 * j + 3 * k;
関数の束縛
関数の束縛には関数名とパラメーターが含まれます。
F#
let function1 a = a + 1
C# の場合、関数と値は区別されるが、普通に関数を書くとこんな感じ。
C#
int function1(int a) { return a + 1; }
通常、パラメーターは、タプル パターンなどのパターンです。
F#
let function2 (a, b) = a + b
タプルはひとつの値なので、空白で並べるパターンとは異なる(カリー化になる)。 C# で定義された関数を F# から呼び出すときは、このタプルを使う。内部的にタプルから複数のパラメーターに直している、と思われる。
C#
int function2(int a, int b) { return a + b; }
ただし、先の function2 を正確に表すにはジェネリックを使うことになる。が、そのままでは + 演算子が使えないので適宜インターフェースを作る必要あり?
C#
class LetBindings<T> { T function2(T a, T b) { return a + b; // これはできない } }
let 束縛式の評価は、最後の式の値になります。
F#
let result = let function3 (a, b) = a + b 100 * function3 (1, 2)
C# の場合は return をつける
C#
int function3(int a, int b) { return a + b; } int test() { return 100 * function3(1, 2); }
ラムダ式の場合は、関数型表記になるので最後のreturnは省略できる。
C#
void test2() { Func<int, int, int> function3 = (a, b) => a + b; int result = function3(1, 2); }
型の注釈
パラメーターの型を整数型にした、function1 の完全な型の注釈は次のようになります。
F#
let function1 (a: int) : int = a + 1
F# の場合は型を指定するのがデフォルトだが、C# の場合は型指定をするのがデフォルト。
C#
int function1( int a ) { return a + 1; }
クラス内の let 束縛
プライベート フィールドとして field1 と field2 を定義する MyClass クラスのコード例を次に示します。
F#
type MyClass(a) = let field1 = a let field2 = "text" do printfn "%d %s" field1 field2 member this.F input = printfn "Field1 %d Field2 %s Input %A" field1 field2 input
クラスの中で do を使うとコントラクタで動く。このあたりは、C# のほうが整然としているかも。
C#
public class MyClass { private int field1; private string fiedl2 = "text"; public MyClass(int a) { this.field1 = a; Console.WriteLine("{0} {1}", this.field1, this.fiedl2); } void F(string input) { Console.WriteLine("Field1 {0} Field2 {1} Input {2}", this.field1, this.fiedl2, input ); } }
let 束縛の型パラメーター
モジュール レベル、型、またはコンピュテーション式の let 束縛では、明示的な型パラメーターを使用できます。 関数の定義内など、式の let 束縛では、型パラメーターを使用できません。
C# だとどうなのか?は分からず。
let 束縛に対する属性
属性はモジュール内の最上位の let 束縛に適用できます。
F#
[<Obsolete>] let function1 x y = x + y
属性の書き方は同じ
C#
[Obsolete] int function1( int x, int y ) { return x + y ; }
スコープおよびユーザーはバインディングを可能にする
モジュールのユーザーはこの場合、開いている Module1 インポート宣言を使用して開き、モジュールを、その直接参照します function1 をできます。
F#
module Module1 = let function1 x = x + 1.0 module Module2 = let function2 x = Module1.function1 x open Module1 let function3 x = function1 x
C# の場合、namespace を使ってもいいが、static method を使ったほうがそれらしい。
C#
public class Module1 { public static double function1(double x) { return x + 1.0; } } public class Module2 { public static double function2(double x) { return Module1.function1(x); } }