Mais conteúdo relacionado Semelhante a 関数型言語&形式的手法セミナー(3) (20) 関数型言語&形式的手法セミナー(3)4. Microsoft Visual F#
Visual Studio 2010から搭載された.NET新言語。
2010年4月発売。
言語の開発自体は2000年頃から行われていた。
OCamlと呼ばれる言語を基礎としている。
メイン開発者の
Don Syme(Microsoft Resarch)
4
6. F#の特長
静的型付け関数型言語 非同期/並列ライブラリ
型推論 単位付き浮動小数点
判別共用体とパターン コード引用符(マクロ)
マッチ モジュールの容易な拡張
.NET環境で動作 インタラクティブ環境
シーケンス(遅延リスト) IDEによる支援
コンピュテーション式
6
11. nullチェックは忘れやすい!
public Double roc(List<Double> values, int param, int offset) {
if(values == null || offset < 0 ||
offset >= values.size() - param || param < 1) {
return null;
}
Double c1 = values.get(offset + param);
Double c2 = values.get(offset);
return c2 / c1 * 100; チェック漏れ!
}
11
15. 値が「ない」状態を判別できる
option型
type ‘a option =
None nullの代わり
| Some of ‘a
値がない状態のNoneと値がある状態のSome(v)の重ね合
わせ(共用体)。
option型は中身を取り出さない限り具体的に使えない。
これでnullチェックを忘れるという事はなくなる。
F#ではoption型が標準でサポート。
15
16. option型で書き直してみる
let roc values param offset =
option {
let! v = values
if offset >= 0 && offset < v.size() - param && param > 0 then
let! c1 = v.get(offset + param)
let! c2 = v.get(offset)
if c1 <> 0 then
return c2 / c1 * 100
}
16
20. Javaで書いてみる
public ArrayList<Integer> subList( ArrayList<Integer> ary ) {
ArrayList<Integer> result = new ArrayList<Integer>();
if( ary != null && ary.size() >= 2) {
for( int i = 0; i < ary.size() – 2; i++ ) {
result.add(ary.get(i) – ary.get(i + 1));
}
}
return result;
}
20
28. こんなプログラムを書いたことは
ありませんか?
for ( Product product : ps ) {
ArrayList<Sell> sells = loadMothlySells(product);
BigDecimal msale = new BigDecimal(0.);
for( Sell sell : sells ) {
msale = sell.sale.add(msale); データベースアクセス
}
writeMonthlySales(product, msale);
}
28
30. 単体テストしやすいように
let takeMontlySells product sells =
product,
Seq.fold (fun msale sell -> sell.sales.add(msale)) 0D) sells
副作用
なし
let makeMothlySells products loader
products
|> Seq.map takeMontlySells (loader product)
let _ =
DBアクセス
makeMontlySells products (LoadMontlySells) 切り出し
|> Seq.iter writeMontlySells
30
34. 線引き機能の実装(概略)
enum CampasMouseListenerMode { Normal, Line; }
class CampasMouseListener implements MouseListener {
CampasMouseListenerMode mode; Lineモードでしか使わな
CampasPoint startPoint; い。暗黙のお約束。
public void mouseMoved( MouseEvent event ) {
}
public void mouseClicked( MouseEvent event ) {
}
}
34
36. それ何て判別共用体?
こういうenumの事を
判別共用体(F#)とかケースクラス(Scala)とか
バリアント(OCaml)とかデータ構築子( Haskell)
と呼びます。
36
37. F#で書き直すと
type mode = Normal | Line of campasPoint
match mode with
Normal ->
| Line startPoint ->
37
39. 様々な応用例
トランプ
type mark = Spade | Heart | Diamond | Club
type card = Joker | Card of mark * int
バイナリツリー構造
type ‘a tree = Node of ‘a tree * ‘a tree | Leaf of ‘a
整数の足し算、引き算
type expr = Const of int
| Add of expr * expr
| Sub of expr * expr
39
42. イベントドリブンプログラミング
の煩雑さ
1. イベント発生後の処理として直列繋ぎしか想定さ
れていない。(柔軟性の不足)
2. 引数による値の受け渡しではなく、もっとスコー
プの広い変数への代入と参照によって繋がりが作
られていくので、暗黙のお約束が増えていく。
(モジュラリティの欠如)
42
44. イベントハンドラは
イベントを受け取ったら
新しいイベントを返せばいいのでは?
(Observerパターンの連鎖)
44
45. 例えばこんなイベント処理を
考えてみます
Request inside process
chain
Request
Event
Response
chain
45
46. F#ではこう書けます
同じイベントから派生
した二系統のチェーン
RequestEvent
|> Observer.map (fun req -> response1 req)
|> Observer.choose (fun r1 -> response2 r1)
|> Observer.choose (fun r2 -> response3 r2)
イベント間で値の
受け渡しができる
RequestEvent ので、モジュラリ
|> Observer.map (fun req -> process1 req) ティアップ。
|> Observer.choose (fun r1 -> process2 r1)
|> Observer.choose (fun r2 -> process3 r2)
46
51. 関数プログラミングによる
加速まとめ
nullを無くして煩雑なチェックから解放。
forループの代わりにmap, foldで簡潔に。
副作用のない関数群で簡単単体テスト。
暗黙のお約束を無くして脳の負担を軽減。
イベント処理を関数的にすっきり記述。
51