58. 自動的な型推論
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" 4
11 (* - : bool = true *)
val~は実際REPLで評価した際に推論、表示される
58
59. 自動的な型推論
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" 4
11 (* - : bool = true *)
->は関数のシグネチャを表し、最後のboolが返値
59
60. 自動的な型推論
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" 4
11 (* - : bool = true *)
10行目、関数適用は並べるだけ
60
61. その他のデータ型
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
複合的な型も同様に推論
66. 多相で高階の関数
1 (* Infix operator *)
2 (* Normally, you should use the one
3 in the Pervasives module(standard library). *)
4 let ( |> ) x f = f x
5 (* val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun> *)
6
7 List.filter_map
8 (* 'a list -> f:('a -> 'b option) -> 'b list = <fun> *)
66
'a 'b が型変数
関数適用時にそれぞれが1つに定まれば良い
67. 多相で高階の関数
1 (* Infix operator *)
2 (* Normally, you should use the one
3 in the Pervasives module(standard library). *)
4 let ( |> ) x f = f x
5 (* val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun> *)
6
7 List.filter_map
8 (* 'a list -> f:('a -> 'b option) -> 'b list = <fun> *)
67
xが'aの時、fが'aをとり'bを返す関数
fにxを適用し結果として’b型の値を返す
68. 多相で高階の関数
1 (* Infix operator *)
2 (* Normally, you should use the one
3 in the Pervasives module(standard library). *)
4 let ( |> ) x f = f x
5 (* val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun> *)
6
7 List.filter_map
8 (* 'a list -> f:('a -> 'b option) -> 'b list = <fun> *)
68
filter_mapは'aのリストとその各要素に
適用する関数fをとり適用した結果のリストを返す
69. 多相で高階の関数
1 (* Infix operator *)
2 (* Normally, you should use the one
3 in the Pervasives module(standard library). *)
4 let ( |> ) x f = f x
5 (* val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun> *)
6
7 List.filter_map
8 (* 'a list -> f:('a -> 'b option) -> 'b list = <fun> *)
69
更にfの返値で引数にとった要素の
取捨選択(Some or None)が可能
70. 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 in
10 | | if eval l' then Some l' else None)
11 |> count_groups
12 |> Hashtbl.iter ~f:(fun ~key ~data ->
Printf.printf "%s = %d, " key data)
具体例として拙コードよりcsv処理の抜粋
(弊学同系には”ジャバ,car.csv”で伝わって)
70
71. 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 in
10 | | if eval l' then Some l' else None)
11 |> count_groups
12 |> Hashtbl.iter ~f:(fun ~key ~data ->
Printf.printf "%s = %d, " key data)
let()= はエントリポイントと見做して下さい
精読は必要ありませんが、流れは次の通り
71
72. 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 in
10 | | if eval l' then Some l' else None)
11 |> count_groups
12 |> Hashtbl.iter ~f:(fun ~key ~data ->
Printf.printf "%s = %d, " key data)
csv読み込み|>条件に合うデータ抽出
|>幾つかのグループに分類して数を集計
|>結果の列挙
72
73. 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 in
10 | | if eval l' then Some l' else None)
11 |> count_groups
12 |> Hashtbl.iter ~f:(fun ~key ~data ->
Printf.printf "%s = %d, " key data)
名前付き引数~f:に要素毎の処理を部分適用
group関数は「分類方法,分類の初期値,畳み込み」の
3つの関数をとる
73
74. 多相と高階のメリット
• ロジックの分離(汎用化)
▶ 全体の流れ (let (|>) x f = f x etc…)
▶ 渡されるデータ構造に対する処理の方針
(filter_map,group,iter etc…)
▶ 各要素に対する処理 (無名関数 fun etc…)
• それぞれ独立に実装、検証、組み合わせ可能
74
79. 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 | Nil
6 | 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"を加えた物
80. 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 | Nil
6 | 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 <型変数> <型名> = <定義>
81. 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 | Nil
6 | 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はコンストラクタと呼ばれる
82. 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 | Nil
6 | 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以降の型の値を引数にとる
83. 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 | Nil
6 | 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
*はタプル(直積型)
84. 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 | Nil
6 | 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とあるように、再帰的に定義可能
85. 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 | Nil
6 | 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型となる
86. 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 | Nil
6 | 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は等価な表現
87. 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_children
11 and char_to_children = (char * trie) list
87
keyは適当に定義したということで…
andは相互再帰できるtype
88. 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 * expr
10 | If of expr * expr * expr
11 | Fun of name * name * ty * ty * expr
12 | Apply of expr * expr
88
[ミニ言語の実装]等を見ると使われ方が分かります
92. e.g.) FizzBuzz
1 let fizzbuzz i = match i mod 3, i mod 5 with
2 | 0, 0 -> "FizzBuzz"
3 | 0, _ -> "Fizz"
4 | _, 0 -> "Buzz"
5 | _ -> string_of_int i
6
7 let () =
8 for i = 1 to 100 do print_endline @@ fizzbuzz i done
92
modは剰余の中置演算子
string_of_int はintからstringへのキャスト関数
@@は|>の逆向きの関数適用
93. 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 in
5 aux j []
6
7 let () =
8 List.iter
(fun x -> x |> fizzbuzz |> print_endline) (1 -- 100)
93
recはこの関数が再帰する事を示す
let…inは宣言後にinに続く式を評価するという意味
95. リストの畳込み関数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 with
10 | | || None -> acc
11 | | || Some x -> x :: acc)
95
例えばfoldl 0 [x1;x2;x3] (+)と適用した際に
(((0 + x1) + x2) + x3)となるのが畳み込み(fold-left)
96. リストのパターン( :: )
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 with
10 | | || None -> acc
11 | | || Some x -> x :: acc)
96
| [] -> リストが空であるならば
| hd :: tl -> 先頭をhd,残りをtlと割当て可能ならば
97. ヴァリアントのパターン
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 with
10 | | || None -> acc
11 | | || Some x -> x :: acc)
97
filter_mapはSomeに包んだ返値のみのリストを構築する
Optionに限らずヴァリアントはコンストラクタでマッチ