Presentation is loading. Please wait.

Presentation is loading. Please wait.

(Rubyistのための) 超音速:ML入門

Similar presentations


Presentation on theme: "(Rubyistのための) 超音速:ML入門"— Presentation transcript:

1 (Rubyistのための) 超音速:ML入門
福盛秀雄 Ver

2 準備運動 let rec factorial n = if n = 1 then 1 else factorial (n - 1) * n
階乗の計算 関数名 引数 let rec factorial n = if n = 1 then 1 else factorial (n - 1) * n

3 こんな書き方も let rec factorial = function | 1 -> 1
| n -> factorial (n - 1) * n 引数の「パターン」を記述

4 並べてみる let rec factorial n = if n = 1 then 1 else factorial (n - 1) * n
let rec factorial = function | 1 -> 1 | n -> factorial (n - 1) * n 下の方が「ML的スタイル」

5 対話型環境を使ってみる $ ocaml Objective Caml version #

6 ふつ~の計算 コロン二つで式の評価 # ;; - : int = 579 結果の表示

7 ふつ~の計算!? 浮動小数点の足し算は +. # ;; - : float = 579. 普通じゃないよ!

8 「暗黙の型変換」? # 123.0 +. 456;; Characters 9-12: 123.0 +. 456;; ^^^
んなものは無い。 浮動小数点演算と 整数演算を混ぜてみる # ;; Characters 9-12: ;; ^^^ This expression has type int but is here used with type float (当然のように) エラーとなる

9 これならOK # 123.0 +. float_of_int 456;; - : float = 579.

10 変数の定義 # let a = 1;; val a : int = 1 # let x = “abc”;;
val x : string = “abc” 定義された変数の型が表示される

11 “int -> int”型の関数“f”が定義された
関数の定義 関数の定義もlet 関数名、引数の順に記述 # let f x = x + 1;; val f : int -> int = <fun> “int -> int”型の関数“f”が定義された

12 (OCamlでは通常)スペースで区切って並べる
関数の定義(2) 複数の引数がある場合、 (OCamlでは通常)スペースで区切って並べる # let g x y = x * y;; val g : int -> int -> int = <fun> これをなんと読む? →「二つのintを順に受け取り、intを返す関数」

13 「関数」と「変数」の区別は? # let g = f;; val g : int -> int = <fun>
本質的には両者の間に明確な区別はない(?)。 関数を別の変数に束縛したり、 別の関数の引数にしたりすることもできる # let f x = x + 1 val f : int -> int = <fun> # let g = f;; val g : int -> int = <fun> # g 1;; - : int = 2 変数gに 関数fを束縛

14 Rubyのブロックに似ていないこともない
無名関数 名前の通り「名前の無い関数」 Rubyのブロックに似ていないこともない Ruby: {|x| x + 1} fun x -> x + 1 OCaml: ちなみにOCamlにて let f x = x + 1 と let f = fun x -> x + 1 は等価

15 付けないと “Unbound value factorial”
再帰を示す“rec” 再帰関数の定義には“rec”を付ける # let rec factorial n = if n = 1 then 1 else factorial (n - 1) * n;; val factorial : int -> int = <fun> 付けないと “Unbound value factorial” というエラーとなる

16 左辺のcounterと右辺のcounterは
関数型言語の特徴 # let counter = 0 ;; val counter : int = 0 # let count () = let counter = counter + 1 in counter;; val count : unit -> int = <fun> 変数への「代入」はできない 左辺のcounterと右辺のcounterは 別のもの counterは常に0のため count()の結果は常に1 # count ();; - : int = 1

17 関数型言語の特徴(2) ループは書けない(書かない) →再帰を使う 変数は変更できない →計算の途中経過は引数と 返り値に入れておく
変数はimmutable→代入はできない 関数は同じ引数に対して必ず同じ値を返す ループは書けない(書かない)  →再帰を使う 変数は変更できない  →計算の途中経過は引数と    返り値に入れておく

18 関数型言語の特徴(3) 「計算の途中経過は引数と 返り値に入れておく」 どうやって実現? 値の定義:強力なデータ型
「計算の途中経過は引数と  返り値に入れておく」 どうやって実現? 値の定義:強力なデータ型 値の参照:強力なパターンマッチング

19 リスト(list)とタプル(tuple)
;で区切る # [1;2;3];; - : int list = [1; 2; 3] タプル # (1,2,3);; - : int * int * int = (1, 2, 3)

20 リストのつくりかた # 1::[2;3];; - : int list = [1; 2; 3] # 1::2::3::[];;
[1;2;3]と書くほかにも… 要素とリストをコロン二つで連結 # 1::[2;3];; - : int list = [1; 2; 3] []は空リスト # 1::2::3::[];; - : int list = [1; 2; 3]

21 レコード型 # type rt = {a : int; b : string};;
“a”,”b”を持つ レコード型“rt”を定義 # type rt = {a : int; b : string};; type rt = { a : int; b : string; } # let rv = {a=1; b="xyz"};; val rv : rt = {a = 1; b = "xyz"} “rt”型の変数“rv”が定義された

22 ヴァリアント型 # type vt = Apple | Banana | Orange;;
“ Cのenum”的な使い方 # type vt = Apple | Banana | Orange;; type vt = Apple | Banana | Orange # let vv = Apple;; val vv : vt = Apple

23 ヴァリアント型(2) # type vt2 = Ival of int | Fval of float;;
値つきのヴァリアント型を定義 # type vt2 = Ival of int | Fval of float;; type vt2 = Ival of int | Fval of float # let vvi = Ival 0;; val vvi : vt2 = Ival 0

24 パターンマッチング let rec factorial = function | 1 -> 1
整数値に対するパターンマッチの例 let rec factorial = function | 1 -> 1 | n -> factorial (n - 1) * n

25 “Pretty Print List” - 「文字列のリスト」を「文字列」へ変換
パターンマッチング(2) リストに対するパターンマッチの例 “Pretty Print List” - 「文字列のリスト」を「文字列」へ変換 let rec pp_list = function | [] -> "" | [x] -> x | x :: xs -> x ^ " " ^ pp_list xs xはリストの先頭 xsはリストの残り ^は文字列の連結 # pp_list;; - : string list -> string = <fun> # pp_list [“str1”;”str2”;”str3”];; - : string = “str1 str2 str3”

26 パターンマッチング(3) ヴァリアントに対するパターンマッチの例 type htmlstr = | UnSafe of string
UnSafeはサニタイズされていないHTML文字列 Safeはサニタイズ済みのHTML文字列(のつもり) type htmlstr = | UnSafe of string | Safe of string let concat h1 h2 = match h1, h2 with | UnSafe(s1), UnSafe(s2) -> UnSafe(s1 ^ s2) | UnSafe(s1), Safe(s2) -> UnSafe(s1 ^ s2) | Safe(s1), UnSafe(s2) -> UnSafe(s1 ^ s2) | Safe(s1), Safe(s2) -> Safe(s1 ^ s2) 二つの引数に対する パターンマッチング

27 モジュール OCaml: Ruby: 『超』乱暴な説明: module Trig = struct let pi = 3.141592654
let sin x = ... let cos x = end module Trig PI = def Trig.sin(x) # .. end def Trig.cos(x) Trig.cos(0) => 1.0 # Trig.cos 0.0;; - : float = 1.

28 標準ライブラリ Listモジュールが 特によく使われるのでとりあえず紹介: 名前の通りリスト関連の 関数が定義されている

29 Rubyの“collect”イテレータと『ほぼ』同じ(?)
List.map Rubyの“collect”イテレータと『ほぼ』同じ(?) Ruby: [1,2,3].collect {|x| x + 1} => [2, 3, 4] OCaml: # List.map (fun x -> x + 1) [1;2;3];; - : int list = [2; 3; 4]

30 Rubyの“inject”イテレータと『ほぼ』同じ(?)
List.fold_left Rubyの“inject”イテレータと『ほぼ』同じ(?) Ruby: [1,2,3].inject(0) {|sum, element| sum + element} => 6 OCaml: # List.fold_left (fun sum element -> sum + element) 0 [1;2;3];; - : int = 6

31 “ref”で代入可能な変数(参照型変数)を定義
命令型処理 “ref”で代入可能な変数(参照型変数)を定義 # let counter = ref 0 ;; val counter : int ref = {contents = 0} # let count () = counter := !counter + 1; !counter ;; ;でつなげることにより 複数の式を順に評価 :=で代入(letが無いことに注意) !を付けると参照型変数の  実際の値が得られる # count ();; - : int = 1 - : int = 2

32 他にもいろいろありますが… あとは実践あるのみ。 MinCamlのソースコードを 読みに行きましょう。 ということで一旦お開き


Download ppt "(Rubyistのための) 超音速:ML入門"

Similar presentations


Ads by Google