元は" The 90 minute Scheme to C compiler" Marc Feeley (90-min-scc.pdf) 。元の文章との整合性は保証しないよ。CPS が何かわかって、コンパイラを作ることに興味が出たら幸い。
ただし、これだけではコンパイラはできないよ。Scheme で作りたいなら、http://www.eidos.ic.i.u-tokyo.ac.jp/~tau/lecture/scheme_compiler/gen/resume/all.pdf がおすすめ。
将来的に浮動小数点を含むコンパイラを作りたいなら、あらかじめ OCaml をつかったコンパイラを目指した方がよい(らしい)。
https://esumii.github.io/min-caml/jpaper.pdf
https://github.com/esumii/min-caml
A正規形とK正規形というのもある(らしい)。
http://d.hatena.ne.jp/sumii/20071229/p1
論文のThe Essence of Compiling with Continuations には A 正規形の話があり、CPS が否定されているように思った。
元は" The 90 minute Scheme to C compiler" Marc Feeley (90-min-scc.pdf) 。元の文章との整合性は保証しないよ。CPS が何かわかって、コンパイラを作ることに興味が出たら幸い。
ただし、これだけではコンパイラはできないよ。Scheme で作りたいなら、http://www.eidos.ic.i.u-tokyo.ac.jp/~tau/lecture/scheme_compiler/gen/resume/all.pdf がおすすめ。
将来的に浮動小数点を含むコンパイラを作りたいなら、あらかじめ OCaml をつかったコンパイラを目指した方がよい(らしい)。
https://esumii.github.io/min-caml/jpaper.pdf
https://github.com/esumii/min-caml
A正規形とK正規形というのもある(らしい)。
http://d.hatena.ne.jp/sumii/20071229/p1
論文のThe Essence of Compiling with Continuations には A 正規形の話があり、CPS が否定されているように思った。
An invited talk by Xavier Leroy explaining the current state of OCaml at the OCaml Users and Developers Workshop 2014. http://ocaml.org/meetings/ocaml/2014/
In this slide, I described how I love prolog, very very cute language. I'm very wonder why many people loves functional programing languages (lisp, haskell and ocaml), but no one knows about logical programming language, so I tried to introduce the charm points of Prolog.
A powerful macro system makes it possible to implement problem-specific optimisations, as well as zero-cost abstractions. I will present a macro system for OCaml designed by Jeremy Yallop and Leo White that allows for advanced metaprogramming and is seamlessly integrated in OCaml’s module system.
Olivier Nicole is graduating in Computer Science at ENSTA ParisTech, France, and is currently doing an internship at OCaml Labs.
This talk was presented as part of the NetOS Talklet Series (http://talks.cam.ac.uk/show/index/10085) at the University of Cambridge Computer Laboratory, UK.
Using functional programming within an industrial product group: perspectives...Anil Madhavapeddy
We present a case-study of using OCaml within a large product development project, focussing on both the technical and non- technical issues that arose as a result. We draw comparisons between the OCaml team and the other teams that worked on the project, providing comparative data on hiring patterns and cross-team code contribution.
Scala, Haskell and LISP are examples of programming languages using the functional programming paradigm. Join us in this TechTalk to know why functional programming is so important, how to implement some of its core concepts in your existing programming languages, and how functional programming inspired Google's Map Reduce, Twitter's Algebird, and many other technologies.
By Mohammad Ghabboun - Senior Software Engineer, SOUQ.com
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に限らずヴァリアントはコンストラクタでマッチ