T3-310 荒井 省三 エバンジェリスト マイクロソフト株式会社 プログラミング パラダイム F# を使う最初の一歩 文法編 データ型、束縛、タプル、リスト、オペレータ mutable、参照型、匿名関数、多重代入 関数定義、フロー制御、try構文、モジュール 独自の型、パターンマッチ、リスト内包式 パイプライン演算子、非同期ワークフロー まとめ 参考資料 関数型プログラミング ML IPL PLANNER 1954 F# 論理プログラミング APL 1957 1956 OCaml Prolog 1969 1974 1960 1962 VS2010 1979 1995 2000 FORTRAN COBOL 手続き型プログラミング Simula C++ Java C# オブジェクト指向プログラミング 出典:日本語版ウィキペディア 証明そのものを記述する言語 = 手続き型やオブ ジェクト指向 証明をどのような操作で行うかを記述する言語 = メタ言語(ML) ML 自体が関数型プログラミングをサポート 関数をファースト オブジェクトとして持つ ラムダ計算の概念をプログラミング言語として実現 高階関数 カリー化 etc 透過性 (状態を持たないことで、副作用がない) F# は、Microsoft Research のプロジェクト から生まれた 2007 年に Visual Studio ファミリーのサ ポート言語としてアナウンス なぜか? マルチパラダイム モジュール化 メニー コア 汎用言語への関数型プログラミングへの拡張 etc ジェネリック 匿名メソッド ラムダ式 LINQ は、宣言型(関数型)プログラミング(関 数型)の影響みられる 状態を持つアプローチの課題 ユーザーは操作の結果に関心があるのであって、 アプリケーションの状態には関心がない マルチコアやマルチプロセッシング 異なるアプローチが必要になっている MapReduce は関数型プログラミングの考えを応用して いる エリクソンは、ハードなリアルタイムシステム用に Erlang を開発した ユーザー プログラム Map Task1 Map Task3 .... ..... Reduce Task1 output input Map Task2 Reduce Task1 Map Taskn Input files / Map フェーズ Google OSDI2004資料から引用 Reduce フェーズ / output files fsi.exe コンソール Visual Studio プロジェクト コンソール イントロダクション // 軽量記法を適用する #light // コンパイラ ディレクティブ let number = [1..10] // 変数定義(リスト型) let square x = x * x // 関数定義 (* square関数呼び出しをリストに対して行い 結果をリストで返す *) let squares = List.map square number //または、ラムダ式を使用する let squares = List.map (fun x -> x * x) number // 結果を出力する printfn "N^2 = %A" squares Microsoft.Fsharp.Core 型 実装している型 bool System.Boolean int System.Int32 float System.Double string System.String char System.Char seq IEnumerable<'a> obj System.Object ... 静的な型システム(型推論) コンパイル時に決定される 型 型表現 説明 特定の型 type int など リスト 型 list、list<型> [1;2;3] など タプル 型*型 (1,2) など 配列 型 array,type[] [|1;2;3|] など シーケンス seq<type> seq [1;2;3] など 関数 type1 -> type2 x -> x + 2 など、複数の引数は type(n)を繰 り返す void ジェネリック unit void に相当するが、1つの値(空のタプル) ‘a 受け取った型を受け入れる 型パラメータ <type> ジェネリック型の型パラメータ let オペレータ let a =10 // 整数への参照 let test1 x = a + x // 関数への参照 // もしくは、匿名関数への参照 let test1 = fun x -> a + x test1 2 // 関数の呼び出し let a = 20 // 新しい整数への参照 test1 2 // 関数の呼び出し (1, “b” [, .....]) 1, “b” [, .....] タプル用の関数(2要素のみ) fst 最初の要素 snd 2つ目の要素 C# のArrayListに近いデータ型 (型 * 型...) Tuple<T1[,.....]> 複数の値を利用する場合などに良く利用する キー、値の組み合わせの利用が多い 関数への引数など [1; 2[; .....]] C# の List<T> に近い (list) 格納できる要素は、同じデータ型のみ 1::[.....][] [.....]@[.....] // リストの先頭へ追加 // アペンド 名前.[インデックス] // リストを返す関数 List.map 関数や式 リスト [|1; 2[; .....]|] System.Array ( array<データ型>、int[]など) 格納できる要素は、同じデータ型のみ 固定サイズ 名前.[インデックス] // 文字列も擬似配列 名前.[インデックス] <- 値 // 配列を返す関数 Array.map 関数や式 配列 // 代入演算 seq [1; 2[; .....]] または {範囲オペレータ} C# の IEnumerable<T> (seq<T>) 格納できる要素は、同じデータ型のみ //シーケンスを返す関数 Seq.map 関数や式 シーケンス オペレータ 四則演算 関数オペレータ +、-、*、/ ** (二乗)、% (余り)、 pown(二乗)、 符号 +、- ~+、~- (プレフィックス) 比較演算子 =、<、>、<=、>=、<> 論理値演算子 && (And)、|| (or)、or、not 文字連結 +、^ リスト連結 ::、@ タプル操作 fst、snd まるめ操作 round、tuncate 数学関数 sin、cos、tan、sqrt、exp、log ビット操作 <<<、>>>、&&&(論理積)、 |||(論理和)、~~~(否定) ボックス 代入演算子 box、unbox := (ref)、 <- (mutable) let (束縛) n..m :n から m までの数値の集合を作る n..skip..m:n から、skip 単位で n までの集 合を作る マイナス方向は、 skip を活用する リスト、配列、シーケンスで使用可能 スライスは、配列で使用可能 (GetSlice) n..m n.. ..m * :n から mまで :n から最後まで :最初から m まで :全要素 let metable m1 = 10 m1 <- 20 // mutable キーワード // 代入演算に見える // 制限事項は、ローカル変数を内部の関数では書き換 えることができない // 式の内部で使用すると、コンパイラによって不変へ と展開される let a1 = [|1,2,3,4,5|] // 配列要素は mutable a1.[0] <- 10 // 関数内部で配列を書き換え可能に使うには、コンパ イラが不変へと展開できないようにする (a1.[i] など) let mutable m1 = 10 let mf1 = m1 + 100 mf1 m1 <- 5 mf1 m1 // 110が返る // 110が返る // 5 が返る let a1 = [|1,2,3,4,5|] let af1 = a1.[0] + 100// 式を定義 af1 // 101が返る a1.[0] <- 5 af1 // 101が返る let af1 i = a1.[i] + 100 af1 0 // 105が返る let r1 = ref 10 r1 := 20 r1.contents !r1 // 参照型への代入 // 参照型の値 // 参照型の値 let rf1 = !r1 + 10 // 式は不変へと展開 let rf2() = !r + 10 される rf2() // 参照型として展開 される // 30 が返る fun x -> x + 1 // キーワード fun でラムダ式 let f1 x = x + 1 は、以下と等価 let f1 = fun x -> x + 1 キーワード「fun」は、「function」の別名である let (a, b, c) = (1,2,3) let (_, b, _) = (1,2,3) // タプルのアンダースコアは、代入値を捨てる let f1 (a,b) = a + b; // 仮引数のタプルは、多重代入される 束縛 (let) とは、式に対する名前の関連付け 式とは リテラル 計算式 λ式(関数) let a = 10 let f1 = a * 2 let f1() = a * 2 let r1 a = a * 2 :既定が普遍として扱われる :コンパイル時に計算される :呼び出し時に処理される // // // // // リテラル 式と評価、式は単一の値を返す 複数の式で構成されても良い 関数と評価、引数が空のタプル 関数と評価、引数がある コンパイル時点で、参照するアドレスへと変換される 型によって、値へと展開されるか、参照(ref) となる 束縛(バインディング)式 let 名前1 [, 名前2 [, .... ]] = データ in 式 // 名前にデータが束縛されて、式で計算される let x = 1 in x + x let x , y = (“One” , 1 ) in x.Length + y let 関数名 [仮引数1[ .... ]] = 定義 フィボナッチ数を計算する関数 let rec fib x = match x with | 1 -> 1 | 2 -> 2 | x -> fib (x – 1) + fib (x – 2) let rec fib x = if x <= 2 then x else fib (x – 1) + fib ( x -2) recキーワード:再帰関数を定義 matchキーワード:パターンマッチ //指定した順序の実行(;) printfn “hello”; printfn “world” // 条件分岐 (if) if 真偽値式 then 処理 if 真偽値式 then 処理 else 処理 if 真偽値式 then 処理 else 処理 if 真偽値式 then 処理 elif 真偽値式 then 処理 // ループ (for) : コレクションは、list、seq、array for i in コレクション do 処理 for i = 初期値 to 終了値 do 処理 // ループ (while) while (真偽値式) do 処理 try構文は 2種類 // 例外を補足するパターン try 処理 with | 例外のマッチ処理 (パイプ演算子) ... // 終了処理を行うパターン try 処理 finally 終了処理 // try ~ with と finally の複合はサポートされない // 入れ子で組み合わせる 例外を発生させる命令 failwith 文字列 raise(例外オブジェクト) invalid_arg 文字列 : Failure 例外 : 任意の例外 : 引数例外 例外のマッチ | Failer msg -> 処理 メッセージを取得 | :? 例外オブジェクト -> 処理 | _ -> 処理 : Failer例外の :個別の例外を補足 :任意の例外を処理 独自の例外型を使用する exception MyException of 型 : 例外型定義 raise(MyException(“データ”)) module キーワード [名前空間.]モジュール名 を指定する インタラクティブなモジュール定義 module モジュール名 = モジュール本体の定義 モジュールファイル定義 スクリプトの先頭に「module モジュール名」 モジュール名に対する別名 module 別名 = モジュール名 スクリプトファイルの読み込み #load “ファイル名” ディレクティブ モジュール(DLL)への参照 #r “アセンブリ名” ディレクティブ 名前空間の省略 open 名前空間 module m1 = let private a = 10 let f1 x = x + a m1.f1 20 open m1 f1 20 // // // // // ローカル変数 公開関数 30が返る 名前空間 30が返る // lib1.fsx ファイルの内容(モジュール) module m2 let private a = 10 let f1 x = x + a // モジュールファイルの使用 #load “lib1.fsx” // アクセシビリティは以下の3種類 // private、public、internal 目的 別名 構文例 type index = int レコード型 type Person = {Name : string; DateOfBirth : System.DateTime;} 共用型 type Transport = (union) | Car of string * string | Bicycle | Bus of int レコード型 type P = Person of string * の別名 System.DateTime 説明 型に別名を定義する 構造体のようなもの(セミコ ロンは省略可能) {Name = “TecDay” ; new .... } パイプで定義された型のどれ かを値として取る let c1 = Car(“NSX”, “Tokyo”) let c2 = Bicycle let c3 = Bus(100) Person型の別名 Person(“tectday”, new ...) option type ‘a = | None | Some of ‘a option 型は、共用型で定義さ れている 列挙型 type duration = | WHOLE | HALF 共用型の応用 // 型の別名 type index = int let f1 x:index = x * 3 // レコード型 type Person = {Name : string ; DateOfBirth : System.DateTime; } {Name=“TechDays”; DateOfBirth= new System.DateTime(2009,1,27)} // レコード型の別名 type P = Person of string * System.DateTime Person(“TechDays”, new System.DateTime(2009,1,27)) // 共用型 type Transport = | Car of string * string | Bicycle | Bus of int Car(“NSX”, Tokyo) Bicycle Bus(100) // 似通った型の区別 type Dot = {X:int; Y:int} type Point = {X:int; Y:int} let p1 (p:Point) = (p.X, p.Y) let d1 (d:Dot) = (d.X, d.y) let dist p = p.X + p.Y // レコード型のコピー let p2 = {X=1; Y=2} let p3 = {p2 with X=5} // 又は以下の式 let p3 = {X=5; Y=p2.Y} // コンストラクタ パラメータを指定、 () を付けることでクラス type Vector2D(dx:float, dy:float)= // コンストラクタの式 let len = sqrt(dx * dx + dy * dy) // プロパティ用のメンバー let mutable text = “” // インスタンス メンバー (書き方が、インスタンス.メンバー) member v.DX = dx member v.DY = dy member v.Scale(k) = Vector2D(k*dx, k*dy) member v.ShiftX(x) = Vector2D(dx=dx + x, y=dy) member v.ShiftY(y) = Vector2D(dx=dx, dy=dy + y) member v.length = len // 書き換え可能プロパティ(getter と setter を定義) member v.Text with get()=text and set(t)= text <- t // スタティック メンバー static member Zero = Vector2D(dx=0.0, dy=0.0) static member OneX = Vector2D(dx=1.0, dy=0.0) static member OneY = Vector2D(dx=0.0, dy=1.0) let v = Vector2D(3.0, 0.0) v.length v.Scale(2.0).length // メンバーを abstract で定義する type IEncoding = abstract Encode : string -> byte[] abstract Decode : byte[] -> string // インターフェースを継承したインスタンス let myEncoder = let ascii = new System.Text.ASCIIEncoding() { new IEncoding with member x.Encode(s) = ascii.GetBytes(s) member x.Decode(s) = ascii.GetString(s) } // 利用例 myEncoder.Encode(“Test”) myEncoder.Decode(it) // インタフェースの多重継承は、「interface 型 with」を使用す る // クラス定義 type X() = // P は、 getter のみという制約 abstract P : int with get // getter のデフォルト実装 default x.P with get() = 3 // 継承は、 inherit キーワード type Y() = inherit X() override x.P with get() = 4 // オーバーライドは、 override キーワード // 既存のクラスにメソッドを追加する type System.Int32 with member i.Mod() = I % 10 // 利用してみる (6).Mod() (10).Mod() match 文 match 式 with | パターン -> 式 ..... パターン 具体例 タプル (1,2,3) (1,2,(4,5)) リスト [X;Y;X] 配列 または [|X;Y;X|] パターン or パターン かつ パターン and パターン ワイルド カード _ アンダースコア 型 :? null null リスト パターン 説明 [] 空のリスト [_] 1つの要素 [_;_] 2つの要素 _::仮引数 2要素以上で、2要素目を 仮引数で受け取る hd::_ _::tl 1 要素目を取得 最後の要素 hd と tl は、List型のスタティックメ ンバー リストや配列などを返す式 [ for i in 1..10 -> i ] seq { for i in 1..10 -> i } [| for i in 1..10 -> i |] [ for i in 1..10 do yield i ] 結果を次のパイプへ渡す [1..10] |> List.map (fun x -> x * x) [1..10] |> ignore F#では、関数などの戻り値は受け取らなけ ればならない (無視できない) 戻りを持つ関数は、ingoreで戻り値を捨て る 操作例 アップキャスト ダウンキャスト 構文例 (データ :> 型) (upcast( データ):型) 互換性のある型へキャ スト (データ :?> 型) 派生先へキャスト (downcast(データ):型) 型の比較 (データ :? 型) アップキャストした データを指定する ボックス化 box(データ) obj型へキャスト アンボックス化 unbox<型>(データ) open System.Windows.Forms // フォームのインスタンスを作成する let form = new Form(Text="Hello by F#") // プロパティの指定は以下と等価 let btn = let tmp = new Button() tmp.Text <- "MyButton" tmp form.Controls.Add(btn) // フォームを表示 form.Show() // イベントハンドラを追加する btn.Click.Add(fun _ -> MessageBox.Show(“Hello F#”, “F#”) |> ignore // MessageBox.Showメソッドの戻り値を捨てることに注意 open System.Threading;; // 実行スレッドから呼ばれる関数 let printWithThread str = printfn "[ThreadID=%d] %s" Thread.CurrentThread.ManagedThreadId str // 非同期に実行する式(二乗、Sin、Cos )をリストで定義 let evals = let z = 4.0 [ async { do printWithThread "Computing z*z\n" return z * z }; async { do printWithThread "Computing sin(z)\n" return sin(z) }; async { do printWithThread "Computing log(z)\n" return log(z) } ] // 並行実行する式を定義 let awr = async { let! vs = Async.Parallel evals do printWithThread "Computing v1+v2+v3" return (Array.fold_left (fun a b -> a + b) 0.0 vs) } // 実行する let R = Async.Run awr printfn “Result = %f\n” R async キーワード 非同期に実行する式を定義する Async.Pararel 関数 並列実行する式を指定する async 式のリスト Async.Run 関数 async 式を実行する Array.fold_left 関数 ((‘a -> ’b -> ‘a) -> ’a -> ‘b [] -> ’a) (‘a -> ’b -> ‘a) : 二つの引数を取る関数 関数、引数、リスト引数 をとって、値を返す 配列を計算して、1つの値に収束させる F# は、関数型言語の特徴を持っている 基本は、不変 (immutable) 式が基本 (リテラル、計算式、ラムダ式) let は、名前に対する束縛 (バインディング) BCL のクラスは、 mutable として扱う パターンマッチ、パイプラインなどは特徴的 な機能 書けば書くほど、短くできる 並列コンピューティングと不変は相性が良い 関数型プログラミング環境の最適化には、関 数型言語が適している etc アセンブリのロード #r “アセンブリ名” ディレクティブ Assembly.LoadWithPartialName ライブラリへのコンパイル fsc.exe -a スクリプトファイル コンソールアプリへのコンパイル fsc.exe -o ファイル名 スクリプトファイル名 fsc.exe --target exe スクリプトファイル名 Windows アプリへのコンパイル fsc.exe --target winexe スクリプトファイル コンパイラ オプションは、「--help」 インタラクティブシェルと日本語 TAB 補完のために IME が使用不可 fsi.exe --no-readline オプション 本来の用途ではないが、使用可能になる etc 型 説明 リテラル例 .NET bool 真偽値 true, false Boolean byte,sbyte 8ビット符号無し数字、符 号付き 0uy,19uy,0xFFuy, 0y,19y,0xFFy Byte, SByte int16,uint16 16ビット符号付き数字、符 号無し 0s,19s,0x0800s 0us,19us,0x0800us Int16, UInt16 int,int32,uint32 32ビット符号付き数字、符 号無し 0,19,0x0800 0u,19u,0x0800u Int32, UInt32 int64,uint64 64ビット符号付き数字、符 号無し 0L,19L,0x0800L 0UL,19UL,0x0800UL Int64, UInt64 nativeint,unativeint ネイティブな符号付き整数、 0n,19n,0x800n 符号無し 0un,19un,0x0800un IntPtr, UIntPtr single,float32 32ビットIEEE浮動小数点 0.0f,19.7f,1.3e4f Single double,float 64ビットIEEE浮動小数点 0.0,19.7,1.3e4 Double decimal 10進数 0M,19M,19.03M Decimal bigint,bignum 大きな整数 0I,19I, 0N,19N Math.BigInt, Math.BigNum unit 1つの値のみ () Core.Unit ダブルクオーテーション string “文字列” シングルクオーテーション char ‘A’ char のバイト配列 “文字列”B 書式文字 型 説 明 %b bool true か false %s string 文字列 %d,%x,%X,%o,%u int/int32 10進、16進(小文字、大文字)、8進、符号無 %e,%E,%f,%g float 浮動小数点表記、10進数、10進数(コンパク ト) %M %A decimal 何でも any_to_string 関数による書式化 %O 何でも ToStringメソッドによる書式 Foundation of F# 、 Apress Expert F# 、 Apress 上記2冊に対する注意点としては、言語仕 様が現在のものと異なる Real World Functional Programming 、 Manning © 2009 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
© Copyright 2024 ExpyDoc