1 - Microsoft

Download Report

Transcript 1 - Microsoft

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.