F# と C# の記法比較

MSDN F# リファレンスを使い C# と記法を比較する

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);
    }
}