105
関数型 プログラミング入門 的な 20min-talk Nth TUTLT 18/12/2015 105 Pages!

関数型プログラミング入門 with OCaml

  • Upload
    nnwww

  • View
    2.089

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 関数型プログラミング入門 with OCaml

関数型 プログラミング入門

的な

20min-talk Nth TUTLT 18/12/2015

105 Pages!

Page 2: 関数型プログラミング入門 with OCaml

誰だ俺は

• じょんどろ @_Nnwww

• Linux班/Tech Lab班

• 計算機科学を学びたいと思っていたらOCamlに入門していた

• サンタさん知能くれ2

Page 3: 関数型プログラミング入門 with OCaml

そもそも アンケート

3

Page 4: 関数型プログラミング入門 with OCaml

関数型〇〇 聞いたことある人 ?

4

Page 5: 関数型プログラミング入門 with OCaml

使って(いる|いた)人?

5

Page 6: 関数型プログラミング入門 with OCaml

アンケートで分岐

• 少ない

→人間でもわかる関数型プログラミング入門

• 多い

→幽霊型と一般化代数的データ型入門(アドリヴ)

6

Page 7: 関数型プログラミング入門 with OCaml

Caution!

7

Page 8: 関数型プログラミング入門 with OCaml

間違っていたら ツッコミ下さい

8

Page 9: 関数型プログラミング入門 with OCaml

関数型 プログラミング入門

人間でもわかる

20min-talk Nth TUTLT 18/12/2015

39 Pages!

Page 10: 関数型プログラミング入門 with OCaml

たまに聞こえる『関数型プログラミング怖い』

10

Page 11: 関数型プログラミング入門 with OCaml

「とりあえず怖いと言っとけ」

イクナイ (・△・) !

11

Page 12: 関数型プログラミング入門 with OCaml

考え方に共感できれば 分かりやすいし実際便利

12

Page 13: 関数型プログラミング入門 with OCaml

間違って理解しないために 大事なこと

13

Page 14: 関数型プログラミング入門 with OCaml

積極的に信頼できる 専門家の言葉を借りよう !

14

Page 15: 関数型プログラミング入門 with OCaml

引用について

[「関数型言語」に関するFAQ形式の一般的説明 ]

より引用(以降、[ ]はリンクです)

15

Page 16: 関数型プログラミング入門 with OCaml

以降ダブルクォートは引用

16

Page 17: 関数型プログラミング入門 with OCaml

関数型言語とは ?

17

Page 18: 関数型プログラミング入門 with OCaml

関数型言語とは

“厳密には関数型プログラミング言語(functional programming language)の略で、

「関数型プログラミングを推奨・支援する

プログラミング言語」のこと”

• 関数型言語の厳密な境界があるわけではない !

18

Page 19: 関数型プログラミング入門 with OCaml

関数型プログラミングとは ?

19

Page 20: 関数型プログラミング入門 with OCaml

関数型プログラミング(FP)とは

“副作用をできるだけ (あるいは全く) 用いず、

式や関数で計算を表すプログラミングスタイル”

“副作用をまったく用いない関数型プログラム

ないし関数型言語を純粋(pure)、

そうでないものを非純粋(impure)と言います”

20

Page 21: 関数型プログラミング入門 with OCaml

関数型プログラミング(FP)とは

ある式eを関数fに適用しf(e)という式を作る

それを更に関数gに適用しg(f(e))という式へ…

小さな組み合わせから始まり

目的のプログラムを構築するプログラミング

21

Page 22: 関数型プログラミング入門 with OCaml

副作用とは ?

22

Page 23: 関数型プログラミング入門 with OCaml

副作用とは

“「式の値を計算して求める」(評価(evaluation)と言います) 以外の動作”

e.g.) 標準出力の書き込み 大域変数への再代入

・ 副作用が増えるほど不透明なプログラムに23

Page 24: 関数型プログラミング入門 with OCaml

参照透明性

“副作用がない式は、必然的に、評価する (=値を計算する) と常に同じ結果になります。

これを参照透明性(referential transparency)

と言います”

• 参照透明な関数の場合、引数に依って結果が一意に定まる

24

Page 25: 関数型プログラミング入門 with OCaml

関数型プログラミング のメリットは ?

25

Page 26: 関数型プログラミング入門 with OCaml

副作用が少ないと…

• 各式間の独立性が高まる

▶組み合わせによる再利用性と柔軟性向上

▶副作用が多い場合と比較してテストや検証が行い易い

26

Page 27: 関数型プログラミング入門 with OCaml

参照透明であれば…

• 式内の変数に対する破壊的代入が存在しない

▶実行時に変更された変数が想定と異なって発生するエラーの抑制

▶副作用が無いため状況の再現も容易

27

Page 28: 関数型プログラミング入門 with OCaml

オブジェクト指向 プログラミング(OOP)と対立するの ?

28

Page 29: 関数型プログラミング入門 with OCaml

補足: OOPの潮流

• アラン・ケイがSmalltalkで提唱したOOP

(基本の処理単位でもメッセージ式が登場)

“動的なクラス・オブジェクト”

• ストラウストラップがC++で提唱したOOP

“静的な抽象データ型としてのクラス”

黒曜さんのAdC[オブジェクト指向プログラミングとは結局なんなのか]より29

Page 30: 関数型プログラミング入門 with OCaml

今回のOOPは処理・データをまとめる単位のレイヤを指す

30

Page 31: 関数型プログラミング入門 with OCaml

FPとOOPは対立しない

“メジャーなオブジェクト指向言語が命令型言語ベースのため、オブジェクト指向=命令型という誤解もよくありますが、データとそれに対する操作 (メソッド) のまとまり (オブジェクト) を基本にシステムを構築するオブジェクト指向と、「副作用を用いない」関数型プログラミングとは、直交・独立な概念です”

31

Page 32: 関数型プログラミング入門 with OCaml

FPとOOPは対立しない

• (関数型|手続き型)プログラミングはプログラムをどのように記述するかが焦点

• ここでのオブジェクト指向プログラミングはデータと操作をどのように構造化するかが焦点

• 注目している構成単位が異なる(言い換えれば議論しているレイヤが異なる)

32

Page 33: 関数型プログラミング入門 with OCaml

FPとOOPは対立しない

• FP上でOOPを実現している例は幾つもある

• FPではオブジェクト以外の(構造化|抽象化)の手法も存在

▶比較するならそこ

▶今回はそこまで踏み込まない33

Page 34: 関数型プログラミング入門 with OCaml

その他諸々 誤解編

34

Page 35: 関数型プログラミング入門 with OCaml

すごいHの影響

• “遅延評価と純粋・非純粋は直交(独立)な概念であることに注意してください”

• モナドは主に副作用を扱いやすくする等の

目的で使われる事があるが、

「モナドを使うこと→FP」ではない

35

Page 36: 関数型プログラミング入門 with OCaml

こういう話をする時は それ言語-specificな話じゃね

という姿勢も大事

36

Page 37: 関数型プログラミング入門 with OCaml

衒学的、ダメ絶対

• 関数型言語は哲学や宗教と関係がありますか?“ありません。いやひょっとしたらいつか何らかの関係が見出されるかもしれませんが、これまでのところ、まっとうな言説は寡聞にして知りません。”

37

Page 38: 関数型プログラミング入門 with OCaml

そういう手法も有るよという話

• 関数型プログラミングで数学の概念を~

▶オブジェクト以外の抽象化方法として数学を背景に持つ物もある

▶ FPに数学の知識が不可欠という事では無い

知は力であるが門戸を狭める物では無い

38

Page 39: 関数型プログラミング入門 with OCaml

かつて人々と関数型ヴォルデモートとの戦いがあった…

39

Page 40: 関数型プログラミング入門 with OCaml

衒学的な記事を真に受けない

40

Page 41: 関数型プログラミング入門 with OCaml

何かよく分からんけど難しそうなこと言ってる

↓ 怖い、凄いはダメ絶対

41

Page 42: 関数型プログラミング入門 with OCaml

以上言語に依らない説明

42

Page 43: 関数型プログラミング入門 with OCaml

抽象的過ぎるので 言語を導入しよう

43

Page 44: 関数型プログラミング入門 with OCaml

具体的な話はTUT Advent Calendarで!

44

Page 45: 関数型プログラミング入門 with OCaml

From here,

Page 46: 関数型プログラミング入門 with OCaml

Second half of Toyohashi University Too

Long Talk

Page 47: 関数型プログラミング入門 with OCaml

In TUT Advent Calendar

Page 48: 関数型プログラミング入門 with OCaml

関数型 プログラミング入門

OCamlの

more 20min-talk 2nd TUT Advent Calendar 22/12/2015

58 Pages!

Page 49: 関数型プログラミング入門 with OCaml

OCamlをざっくり雰囲気入門

49

Page 50: 関数型プログラミング入門 with OCaml

Caution!!

50

Page 51: 関数型プログラミング入門 with OCaml

ここからは幾つかの言語にも共通する特徴の説明

51

Page 52: 関数型プログラミング入門 with OCaml

広く知られているものを中心に紹介していきますが一般的では無いことに注意

52

Page 53: 関数型プログラミング入門 with OCaml

あくまでOCamlのプログラミング

53

Page 54: 関数型プログラミング入門 with OCaml

[http://ocaml.org/]

54

Page 55: 関数型プログラミング入門 with OCaml

OCamlとは

• 強い静的型付け、非純粋、正格評価

• フランス国立の計算機科学、数学の応用に

関する研究所INRIAが実装

• 関数型プログラミングを中心に

手続き型や構造的部分型付けのOOPをサポート

55

Page 56: 関数型プログラミング入門 with OCaml

OCamlの関数型プログラミング

• 自動的な型推論 (Automatic type inference)

• パラメトリック多相 (Parametric polymorphism)

• 第一級関数 (First-class functions)

• 代数的データ型 (Algebraic data types)

• パターンマッチング (Pattern matching)

56

Page 57: 関数型プログラミング入門 with OCaml

OCamlの関数型プログラミング

• 自動的な型推論 (Automatic type inference)

• パラメトリック多相 (Parametric polymorphism)

• 第一級関数 (First-class functions)

• 代数的データ型 (Algebraic data types)

• パターンマッチング (Pattern matching)

57

Page 58: 関数型プログラミング入門 with OCaml

自動的な型推論

1 (* This is a comment. *) 2 (* let <var_id> = <val> *) 3 let txt = "hello" 4 (* val txt : bytes = "hello" *) 5 6 (* let <fun_id> <args...> = <body> *) 7 let longer_len ls len = String.length ls > len 8 (* val longer_len : bytes -> int -> bool = <fun> *) 9 10 longer_len "hello" 411 (* - : bool = true *)

val~は実際REPLで評価した際に推論、表示される58

Page 59: 関数型プログラミング入門 with OCaml

自動的な型推論

1 (* This is a comment. *) 2 (* let <var_id> = <val> *) 3 let txt = "hello" 4 (* val txt : bytes = "hello" *) 5 6 (* let <fun_id> <args...> = <body> *) 7 let longer_len ls len = String.length ls > len 8 (* val longer_len : bytes -> int -> bool = <fun> *) 9 10 longer_len "hello" 411 (* - : bool = true *)

->は関数のシグネチャを表し、最後のboolが返値59

Page 60: 関数型プログラミング入門 with OCaml

自動的な型推論

1 (* This is a comment. *) 2 (* let <var_id> = <val> *) 3 let txt = "hello" 4 (* val txt : bytes = "hello" *) 5 6 (* let <fun_id> <args...> = <body> *) 7 let longer_len ls len = String.length ls > len 8 (* val longer_len : bytes -> int -> bool = <fun> *) 9 10 longer_len "hello" 411 (* - : bool = true *)

10行目、関数適用は並べるだけ60

Page 61: 関数型プログラミング入門 with OCaml

その他のデータ型

1 let l = ['T'; 'U'; 'T'] 2 (* val l : char list *) 3 4 (* Option type has a value that may be invalid *) 5 let o = Some 100 (* or None *) 6 (* val o : int option *) 7 8 (* Tuple aka product type *) 9 let t = (longer_len, l, o)10 (* val t : (int -> bytes -> bool) * char list * int option *)

61

複合的な型も同様に推論

Page 62: 関数型プログラミング入門 with OCaml

自動的な型推論

• 基本的に特別なアノテーションは必要なし

• FPでは細かな関数の組み合わせが非常に多い

▶後述する多相の推論の有無は可読性に大きな影響

• 強制したければ明示的な指定も可能

• mliファイルにソースの推論結果を自動生成可62

Page 63: 関数型プログラミング入門 with OCaml

OCamlの関数型プログラミング

• 自動的な型推論 (Automatic type inference)

• パラメトリック多相 (Parametric polymorphism)

• 第一級関数 (First-class functions)

• 代数的データ型 (Algebraic data types)

• パターンマッチング (Pattern matching)

63

Page 64: 関数型プログラミング入門 with OCaml

パラメトリック多相/第一級関数

• パラメトリック多相

▶型の一部をパラメータとした時の多相

• 第一級関数

▶第一級オブジェクトとして扱える関数

▶関数を引数や返り値にとる関数が高階関数64

Page 65: 関数型プログラミング入門 with OCaml

補足: 部分適用

一部の引数を束縛した新しい関数の値を返す操作longer_lenの引数lenを7に束縛した関数の値

をlonger_7に束縛している65

1 let longer_len len ls = String.length ls > len2 let longer_7 = longer_len 73 4 longer_7 "Aie" (* false *)5 longer_7 "Aieeeeeeeee" (* true *)

Page 66: 関数型プログラミング入門 with OCaml

多相で高階の関数

1 (* Infix operator *)2 (* Normally, you should use the one3 in the Pervasives module(standard library). *)4 let ( |> ) x f = f x5 (* val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun> *)6 7 List.filter_map8 (* 'a list -> f:('a -> 'b option) -> 'b list = <fun> *)

66

'a 'b が型変数

関数適用時にそれぞれが1つに定まれば良い

Page 67: 関数型プログラミング入門 with OCaml

多相で高階の関数

1 (* Infix operator *)2 (* Normally, you should use the one3 in the Pervasives module(standard library). *)4 let ( |> ) x f = f x5 (* val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun> *)6 7 List.filter_map8 (* 'a list -> f:('a -> 'b option) -> 'b list = <fun> *)

67

xが'aの時、fが'aをとり'bを返す関数fにxを適用し結果として’b型の値を返す

Page 68: 関数型プログラミング入門 with OCaml

多相で高階の関数

1 (* Infix operator *)2 (* Normally, you should use the one3 in the Pervasives module(standard library). *)4 let ( |> ) x f = f x5 (* val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun> *)6 7 List.filter_map8 (* 'a list -> f:('a -> 'b option) -> 'b list = <fun> *)

68

filter_mapは'aのリストとその各要素に

適用する関数fをとり適用した結果のリストを返す

Page 69: 関数型プログラミング入門 with OCaml

多相で高階の関数

1 (* Infix operator *)2 (* Normally, you should use the one3 in the Pervasives module(standard library). *)4 let ( |> ) x f = f x5 (* val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun> *)6 7 List.filter_map8 (* 'a list -> f:('a -> 'b option) -> 'b list = <fun> *)

69

更にfの返値で引数にとった要素の

取捨選択(Some or None)が可能

Page 70: 関数型プログラミング入門 with OCaml

1 let count_groups l = String.Table.group 2 | (fun record -> List.nth_exn record 6) 3 | (fun x -> 1) 4 | (fun x y -> x + 1) l 5 6 let () = 7 In_channel.read_lines "car.csv" 8 |> List.filter_map ~f:(fun l -> 9 | | let l' = String.split ~on:',' l in10 | | if eval l' then Some l' else None)11 |> count_groups12 |> Hashtbl.iter ~f:(fun ~key ~data -> Printf.printf "%s = %d, " key data)

具体例として拙コードよりcsv処理の抜粋

(弊学同系には”ジャバ,car.csv”で伝わって)70

Page 71: 関数型プログラミング入門 with OCaml

1 let count_groups l = String.Table.group 2 | (fun record -> List.nth_exn record 6) 3 | (fun x -> 1) 4 | (fun x y -> x + 1) l 5 6 let () = 7 In_channel.read_lines "car.csv" 8 |> List.filter_map ~f:(fun l -> 9 | | let l' = String.split ~on:',' l in10 | | if eval l' then Some l' else None)11 |> count_groups12 |> Hashtbl.iter ~f:(fun ~key ~data -> Printf.printf "%s = %d, " key data)

let()= はエントリポイントと見做して下さい

精読は必要ありませんが、流れは次の通り71

Page 72: 関数型プログラミング入門 with OCaml

1 let count_groups l = String.Table.group 2 | (fun record -> List.nth_exn record 6) 3 | (fun x -> 1) 4 | (fun x y -> x + 1) l 5 6 let () = 7 In_channel.read_lines "car.csv" 8 |> List.filter_map ~f:(fun l -> 9 | | let l' = String.split ~on:',' l in10 | | if eval l' then Some l' else None)11 |> count_groups12 |> Hashtbl.iter ~f:(fun ~key ~data -> Printf.printf "%s = %d, " key data)

csv読み込み|>条件に合うデータ抽出|>幾つかのグループに分類して数を集計

|>結果の列挙72

Page 73: 関数型プログラミング入門 with OCaml

1 let count_groups l = String.Table.group 2 | (fun record -> List.nth_exn record 6) 3 | (fun x -> 1) 4 | (fun x y -> x + 1) l 5 6 let () = 7 In_channel.read_lines "car.csv" 8 |> List.filter_map ~f:(fun l -> 9 | | let l' = String.split ~on:',' l in10 | | if eval l' then Some l' else None)11 |> count_groups12 |> Hashtbl.iter ~f:(fun ~key ~data -> Printf.printf "%s = %d, " key data)

名前付き引数~f:に要素毎の処理を部分適用group関数は「分類方法,分類の初期値,畳み込み」の

3つの関数をとる73

Page 74: 関数型プログラミング入門 with OCaml

多相と高階のメリット• ロジックの分離(汎用化)

▶全体の流れ (let (|>) x f = f x etc…)

▶渡されるデータ構造に対する処理の方針(filter_map,group,iter etc…)

▶各要素に対する処理 (無名関数 fun etc…)

• それぞれ独立に実装、検証、組み合わせ可能74

Page 75: 関数型プログラミング入門 with OCaml

つまりウォーズマン理論1. 両手の無名関数で100万+100万の200万パワー !!

2. いつもの2倍の畳み込みが加わり、200万×2の400万パワー !!

3. そして、いつもの3倍のPipe Operatorを加えれば、 400万×3のLINQ to Objectsマン !

お前をうわまわる1200万パワーだーっ!!

4. (※OCamlは正格評価なので

省メモリ化はLazyか読込み元での畳み込みが必要)

75

Page 76: 関数型プログラミング入門 with OCaml

OCamlの関数型プログラミング

• 自動的な型推論 (Automatic type inference)

• パラメトリック多相 (Parametric polymorphism)

• 第一級関数 (First-class functions)

• 代数的データ型 (Algebraic data types)

• パターンマッチング (Pattern matching)

76

Page 77: 関数型プログラミング入門 with OCaml

ヴァリアント型(代数的データ型)

• OCamlではヴァリアント型と呼ばれる、以下構文

• 「直積型の総和」…「直和型」… とも

• これを用いて問題や構造を型に変換していく77

type <variant> = | <Tag> [ of <type> [* <type>]... ] | <Tag> [ of <type> [* <type>]... ] | ...

Page 78: 関数型プログラミング入門 with OCaml

分かりにくいので実例

78

Page 79: 関数型プログラミング入門 with OCaml

e.g.) リストの再現

1 (* You can declare ["aaa"; "bbb"] usually *)2 let original_list = "aaa" :: "bbb" :: []

3 (* Variants aka Algebraic data types *)4 type 'a eq_list =5 | Nil6 | Cons of 'a * 'a eq_list

7 (* Equivalent representation *)8 let eq_l = Cons("aaa", Cons("bbb", Nil))9 (* val eq_l : string eq_list *)

79

2行目は空のリストへ"bbb"と"aaa"を加えた物

Page 80: 関数型プログラミング入門 with OCaml

e.g.) リストの再現

1 (* You can declare ["aaa"; "bbb"] usually *)2 let original_list = "aaa" :: "bbb" :: []

3 (* Variants aka Algebraic data types *)4 type 'a eq_list =5 | Nil6 | Cons of 'a * 'a eq_list

7 (* Equivalent representation *)8 let eq_l = Cons("aaa", Cons("bbb", Nil))9 (* val eq_l : string eq_list *)

80

type <型変数> <型名> = <定義>

Page 81: 関数型プログラミング入門 with OCaml

e.g.) リストの再現

1 (* You can declare ["aaa"; "bbb"] usually *)2 let original_list = "aaa" :: "bbb" :: []

3 (* Variants aka Algebraic data types *)4 type 'a eq_list =5 | Nil6 | Cons of 'a * 'a eq_list

7 (* Equivalent representation *)8 let eq_l = Cons("aaa", Cons("bbb", Nil))9 (* val eq_l : string eq_list *)

81

Nil Consはコンストラクタと呼ばれる

Page 82: 関数型プログラミング入門 with OCaml

e.g.) リストの再現

1 (* You can declare ["aaa"; "bbb"] usually *)2 let original_list = "aaa" :: "bbb" :: []

3 (* Variants aka Algebraic data types *)4 type 'a eq_list =5 | Nil6 | Cons of 'a * 'a eq_list

7 (* Equivalent representation *)8 let eq_l = Cons("aaa", Cons("bbb", Nil))9 (* val eq_l : string eq_list *)

82

Consはof以降の型の値を引数にとる

Page 83: 関数型プログラミング入門 with OCaml

e.g.) リストの再現

1 (* You can declare ["aaa"; "bbb"] usually *)2 let original_list = "aaa" :: "bbb" :: []

3 (* Variants aka Algebraic data types *)4 type 'a eq_list =5 | Nil6 | Cons of 'a * 'a eq_list

7 (* Equivalent representation *)8 let eq_l = Cons("aaa", Cons("bbb", Nil))9 (* val eq_l : string eq_list *)

83

*はタプル(直積型)

Page 84: 関数型プログラミング入門 with OCaml

e.g.) リストの再現

1 (* You can declare ["aaa"; "bbb"] usually *)2 let original_list = "aaa" :: "bbb" :: []

3 (* Variants aka Algebraic data types *)4 type 'a eq_list =5 | Nil6 | Cons of 'a * 'a eq_list

7 (* Equivalent representation *)8 let eq_l = Cons("aaa", Cons("bbb", Nil))9 (* val eq_l : string eq_list *)

84

*'a eq_listとあるように、再帰的に定義可能

Page 85: 関数型プログラミング入門 with OCaml

e.g.) リストの再現

1 (* You can declare ["aaa"; "bbb"] usually *)2 let original_list = "aaa" :: "bbb" :: []

3 (* Variants aka Algebraic data types *)4 type 'a eq_list =5 | Nil6 | Cons of 'a * 'a eq_list

7 (* Equivalent representation *)8 let eq_l = Cons("aaa", Cons("bbb", Nil))9 (* val eq_l : string eq_list *)

85

これらNil Consで構成される値がeq_list型となる

Page 86: 関数型プログラミング入門 with OCaml

e.g.) リストの再現

1 (* You can declare ["aaa"; "bbb"] usually *)2 let original_list = "aaa" :: "bbb" :: []

3 (* Variants aka Algebraic data types *)4 type 'a eq_list =5 | Nil6 | Cons of 'a * 'a eq_list

7 (* Equivalent representation *)8 let eq_l = Cons("aaa", Cons("bbb", Nil))9 (* val eq_l : string eq_list *)

86

original_listとeq_lは等価な表現

Page 87: 関数型プログラミング入門 with OCaml

e.g.) Option, 赤黒木, Trie 1 type 'a option = 2 | None 3 | Some of 'a 4 5 type 'a rb_tree = 6 | Empty 7 | Red of 'a rb_tree * key * 'a * 'a rb_tree 8 | Black of 'a rb_tree * key * 'a * 'a rb_tree 9 10 type trie = Trie of int option * char_to_children11 and char_to_children = (char * trie) list

87

keyは適当に定義したということで…

andは相互再帰できるtype

Page 88: 関数型プログラミング入門 with OCaml

e.g.) 簡単な式(雰囲気) 1 type expr = 2 | Var of name 3 | Int of int 4 | Bool of bool 5 | Times of expr * expr 6 | Plus of expr * expr 7 | Minus of expr * expr 8 | Equal of expr * expr 9 | Less of expr * expr10 | If of expr * expr * expr11 | Fun of name * name * ty * ty * expr12 | Apply of expr * expr

88

[ミニ言語の実装]等を見ると使われ方が分かります

Page 89: 関数型プログラミング入門 with OCaml

値が作れるのは分かったけど操作はどうするの

89

Page 90: 関数型プログラミング入門 with OCaml

OCamlの関数型プログラミング

• 自動的な型推論 (Automatic type inference)

• パラメトリック多相 (Parametric polymorphism)

• 第一級関数 (First-class functions)

• 代数的データ型 (Algebraic data types)

• パターンマッチング (Pattern matching)

90

Page 91: 関数型プログラミング入門 with OCaml

パターンマッチング

• match式で[パターン] に応じた分岐と 変数割当てが可能

• パターンを網羅できているか、冗長でないかを コンパイル時にチェックし何か有れば警告してくれる

91

match <value> with| <pattern> -> <result>| <pattern> -> <result> ...

Page 92: 関数型プログラミング入門 with OCaml

e.g.) FizzBuzz

1 let fizzbuzz i = match i mod 3, i mod 5 with2 | 0, 0 -> "FizzBuzz"3 | 0, _ -> "Fizz"4 | _, 0 -> "Buzz"5 | _ -> string_of_int i6 7 let () =8 for i = 1 to 100 do print_endline @@ fizzbuzz i done

92

modは剰余の中置演算子string_of_int はintからstringへのキャスト関数

@@は|>の逆向きの関数適用

Page 93: 関数型プログラミング入門 with OCaml

e.g.) Without a side effect

1 let (--) i j = (* i -- j makes a list from i to j *)2 let rec aux n acc =3 | if n < i then acc else aux (n - 1) (n :: acc)4 in5 aux j []6 7 let () =8 List.iter (fun x -> x |> fizzbuzz |> print_endline) (1 -- 100)

93

recはこの関数が再帰する事を示すlet…inは宣言後にinに続く式を評価するという意味

Page 94: 関数型プログラミング入門 with OCaml

リストを畳み込む関数foldl を起点にfilter_mapを作ってみる

94

Page 95: 関数型プログラミング入門 with OCaml

リストの畳込み関数foldl 1 let rec foldl acc ls f = match ls with 2 | [] -> acc 3 | hd :: tl -> foldl (f acc hd) tl f 4 5 let rev ls = foldl [] ls (fun acc x -> x :: acc) 6 7 let filter_map ls f = 8 rev @@ foldl [] ls 9 | (fun acc elm -> match f elm with10 | | || None -> acc11 | | || Some x -> x :: acc)

95

例えばfoldl 0 [x1;x2;x3] (+)と適用した際に(((0 + x1) + x2) + x3)となるのが畳み込み(fold-left)

Page 96: 関数型プログラミング入門 with OCaml

リストのパターン( :: ) 1 let rec foldl acc ls f = match ls with 2 | [] -> acc 3 | hd :: tl -> foldl (f acc hd) tl f 4 5 let rev ls = foldl [] ls (fun acc x -> x :: acc) 6 7 let filter_map ls f = 8 rev @@ foldl [] ls 9 | (fun acc elm -> match f elm with10 | | || None -> acc11 | | || Some x -> x :: acc)

96

| [] -> リストが空であるならば| hd :: tl -> 先頭をhd,残りをtlと割当て可能ならば

Page 97: 関数型プログラミング入門 with OCaml

ヴァリアントのパターン 1 let rec foldl acc ls f = match ls with 2 | [] -> acc 3 | hd :: tl -> foldl (f acc hd) tl f 4 5 let rev ls = foldl [] ls (fun acc x -> x :: acc) 6 7 let filter_map ls f = 8 rev @@ foldl [] ls 9 | (fun acc elm -> match f elm with10 | | || None -> acc11 | | || Some x -> x :: acc)

97

filter_mapはSomeに包んだ返値のみのリストを構築するOptionに限らずヴァリアントはコンストラクタでマッチ

Page 98: 関数型プログラミング入門 with OCaml

ヴァリアントとパターンマッチング• ヴァリアントは異なる複数の型を

コンストラクタで型付け1つの型として表現できる

• 関数側でパターンを網羅することでヴァリアント型の値を扱う事ができる

• 型の積(タプル,レコード)と和(ヴァリアント系)で様々なデータ構造を表す事ができる

98

Page 99: 関数型プログラミング入門 with OCaml

その他紹介できなかったもの

99

Page 100: 関数型プログラミング入門 with OCaml

OCamlな機能のみなさま

• 多相ヴァリアント、 一般化代数的データ型

▶ ヴァリアントのゆかい(強力)な仲間たち

• 命令型プログラミング(副作用akaダークパワー)

▶ 非純粋だからって疎かにしている訳ではない !

[手続き型言語OCaml]

[ハスケロウ、破壊的代入はいいぞ!!] 100

Page 101: 関数型プログラミング入門 with OCaml

OCamlな機能の諸兄

• モジュール、ファンクタ、第一級モジュール

▶ 前述したオブジェクト以外の(構造化|抽象化)

▶ 最もOCaml(というかml族)な機能の1つかも?

• 構造的部分型付けのオブジェクト

▶ 強力だが[過ぎる側面] も…

101

Page 102: 関数型プログラミング入門 with OCaml

今回は幾つかの言語にも共通する特徴の説明

102

Page 103: 関数型プログラミング入門 with OCaml

つまりOCamlらしい特徴はここから…

103

Page 104: 関数型プログラミング入門 with OCaml

結論104

Page 105: 関数型プログラミング入門 with OCaml

とても説明しきれないので

[Real World OCaml] を読もう!

105