C#で学ぶF#入門で使用する資料を書いていきます。
F#が分かりにくいと感じる原因は、主に以下の2種類だと思う。
今回は前者の壁に的を絞る。両者は完全に分離しているわけではないので、後者の領域も多少は言及する。個人的には構文が簡潔で短く書けるのが良いと思う。
2通りの書き方ができる。
型情報が自己完結していないと外部(呼び出し側)から影響を受ける。
予期しない型推論に引きずられる可能性があるため、引数には型情報を付けるのが無難。戻り値は型推論に任せても特に問題はない。
13:20 - 13:30 | F#の特徴 |
13:30 - 13:40 | IDEの使い方(C#) |
13:40 - 13:50 | IDEの使い方(F#) |
14:00 - 14:10 | ハローワールド |
14:10 - 14:20 | 条件式 |
14:20 - 14:30 | 関数 |
14:30 - 14:50 | クラス(C#・F#共通) |
15:00 - 15:10 | 参照 |
15:10 - 15:30 | クロージャ |
15:30 - 15:50 | ループ |
16:00 - 16:20 | クラス(F#特有) |
16:20 - 16:50 | 判別共用体 |
17:00 - 17:30 | 四則演算パーサ |
- F#の構文は見慣れないものだと思うので、C#と比較しながら構文に慣れることを中心にする。
- 関数型特有の概念の説明には重点を置かないが、その導入になるようには意識する。
- 一気に関数型に飛ばないで、ベターC#として慣れていくイメージ。
F#が分かりにくいと感じる原因は、主に以下の2種類だと思う。
- 構文の異質さ(C系言語などと比較して)
- 関数型の考え方
今回は前者の壁に的を絞る。両者は完全に分離しているわけではないので、後者の領域も多少は言及する。個人的には構文が簡潔で短く書けるのが良いと思う。
using System; class Test { static void Main() { Console.WriteLine("Hello, World!"); } }
- C#はMainメソッドが必須で、クラスで包む必要がある。
printfn "Hello, World!";;
- F#のテストにfsiは必須
- セミコロンに注意
- F#のソースではセミコロンの必要ないlight構文がデフォルト
- Visual Studio上で[Alt]+[Enter]の方法も説明。
- 一行テストだと手軽で良いが、複数行だと選択が必要で面倒。
using System; class Test { static void Main() { var a = 1; Console.WriteLine("{0}", a); } }
- C#ではMainやクラスで包む必要がある。
using System; class Test { static void inc(int x) { return x + 1; } static void add(int x, int y) { return x + y; } static void Main() { Console.WriteLine("{0}", inc(1)); Console.WriteLine("{0}", add(1, 2)); } }
let inc = fun x -> x + 1 printfn "%d" (inc 1)
- 関数の定義も変数の束縛と同列に行う。
- cf. let a = 1
- 関数単体で取り出した使い方はF# Interactiveで
let inc = fun x -> x + 1;; inc 1;; (inc 1);; inc(1);; (fun x -> x + 1) 1;;
- printfnを使わなくても良いので便利
- 関数の呼び方は色々書けるけど、半ば遊び(要説明)
- 最後の例は関数を束縛せずにインラインで使っている
let add = fun x -> fun y -> x + y printfn "%d" (add 1 2)
- 2引数は高階関数でクロージャを含む
- cf. fun x -> (fun y -> x + y)
- protectedがない以外は、C#と同じことが書ける。
- F#で推奨されないことは、書けるけど面倒にしてある印象。(あくまで推測)
- レコード型と匿名クラスの比較。
- valが面倒で、letはprivateだけとか、memberは前方参照OKとか。
2通りの書き方ができる。
let test1 a b = a + b let test2(a, b) = a + b
- 厳密にはこの2つは異なるが、F#的には前者が推奨。
- 前者はカリー化、後者はタプルと関係がある。深入りしないでさらっと流す。
型情報が自己完結していないと外部(呼び出し側)から影響を受ける。
let test a b = a + b // int -> int -> int printfn "%d" (test 1 2)
let test a b = a + b // string -> string -> string printfn "%s" (test "a" "b")
let test a b = a + b // int -> int -> int printfn "%d" (test 1 2) printfn "%s" (test "a" "b") // エラー
let test a b = a + b // string -> string -> string printfn "%s" (test "a" "b") printfn "%d" (test 1 2) // エラー
予期しない型推論に引きずられる可能性があるため、引数には型情報を付けるのが無難。戻り値は型推論に任せても特に問題はない。
let test1 (a:int) (b:int) = a + b let test2 (a:string) (b:string) = a + b
- プロジェクト作成のときに選択できる
- neueccさんの記事でC#との対比が読めます: http://neue.cc/2009/11/09_214.html
最新コメント