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

32
1 (Rubyist のののの ) のののML のの のののの http://fukumori.org Ver.2005.07.30

description

(Rubyist のための ) 超音速: ML 入門. 福盛秀雄 http://fukumori.org. Ver.2005.07.30. 準備運動. 階乗の計算. 関数名. 引数. 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. 引数の「パターン」を記述. 並べてみる. - PowerPoint PPT Presentation

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

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

1

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

福盛秀雄http://fukumori.org

Ver.2005.07.30

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

2

準備運動

let rec factorial n = if n = 1 then 1 else factorial (n - 1) * n

関数名 引数階乗の計算

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

3

こんな書き方も

let rec factorial = function | 1 -> 1 | n -> factorial (n - 1) * n

引数の「パターン」を記述

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

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 的スタイル」

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

5

対話型環境を使ってみる

$ ocaml Objective Caml version 3.08.3

#

$ ocaml Objective Caml version 3.08.3

#

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

6

ふつ~の計算

# 123 + 456;;- : int = 579# 123 + 456;;- : int = 579

コロン二つで式の評価

結果の表示

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

7

ふつ~の計算 !?

# 123.0 +. 456.0;;- : float = 579.# 123.0 +. 456.0;;- : float = 579.

普通じゃないよ!

浮動小数点の足し算は +.

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

8

「暗黙の型変換」 ?

# 123.0 +. 456;;Characters 9-12: 123.0 +. 456;; ^^^This expression has type int but is here used with type float

# 123.0 +. 456;;Characters 9-12: 123.0 +. 456;; ^^^This expression has type int but is here used with type float

んなものは無い。浮動小数点演算と

整数演算を混ぜてみる

(当然のように)エラーとなる

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

9

これなら OK

# 123.0 +. float_of_int 456;;- : float = 579.# 123.0 +. float_of_int 456;;- : float = 579.

int -> float の関数

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

10

変数の定義

# let a = 1;;val a : int = 1# let a = 1;;val a : int = 1

# let x = “abc”;;val x : string = “abc”# let x = “abc”;;val x : string = “abc”

let < 変数名 > = ... で定義

定義された変数の型が表示される

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

11

関数の定義

# let f x = x + 1;;val f : int -> int = <fun># let f x = x + 1;;val f : int -> int = <fun>

関数の定義も let 関数名、引数の順に記述

“int -> int” 型の関数“ f” が定義された

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

12

関数の定義 (2)

# let g x y = x * y;;val g : int -> int -> int = <fun># let g x y = x * y;;val g : int -> int -> int = <fun>

複数の引数がある場合、(OCaml では通常 ) スペースで区切って並べる

これをなんと読む ?→ 「二つの int を順に受け取り、 int を返す関数」

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

13

「関数」と「変数」の区別は ?

# let f x = x + 1val f : int -> int = <fun>

# let g = f;;val g : int -> int = <fun># g 1;;- : int = 2

# let f x = x + 1val f : int -> int = <fun>

# let g = f;;val g : int -> int = <fun># g 1;;- : int = 2

変数 g に関数 f を束縛

本質的には両者の間に明確な区別はない(?)。関数を別の変数に束縛したり、別の関数の引数にしたりすることもできる

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

14

無名関数

{|x| x + 1}

名前の通り「名前の無い関数」Ruby のブロックに似ていないこともない

fun x -> x + 1

ちなみに OCaml にてlet f x = x + 1 とlet f = fun x -> x + 1 は等価

Ruby:

OCaml:

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

15

再帰を示す“ rec”

# let rec factorial n = if n = 1 then 1 else factorial (n - 1) * n;;val factorial : int -> int = <fun>

# let rec factorial n = if n = 1 then 1 else factorial (n - 1) * n;;val factorial : int -> int = <fun>

再帰関数の定義には“ rec” を付ける

付けないと “ Unbound value factorial”というエラーとなる

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

16

関数型言語の特徴# let counter = 0 ;;val counter : int = 0# let count () = let counter = counter + 1 in counter;; val count : unit -> int = <fun>

# let counter = 0 ;;val counter : int = 0# let count () = let counter = counter + 1 in counter;; val count : unit -> int = <fun>

# count ();;- : int = 1# count ();;- : int = 1

# count ();;- : int = 1# count ();;- : int = 1

変数への「代入」はできない左辺の counter と右辺の counter は

別のもの

counter は常に 0 のためcount() の結果は常に 1

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

17

関数型言語の特徴 (2)

•ループは書けない(書かない) →再帰を使う•変数は変更できない →計算の途中経過は引数と   返り値に入れておく

•変数は immutable→ 代入はできない•関数は同じ引数に対して必ず同じ値を返す

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

18

関数型言語の特徴 (3)

値の定義:強力なデータ型値の参照:強力なパターンマッチング

「計算の途中経過は引数と 返り値に入れておく」

どうやって実現?

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

19

リスト (list) とタプル(tuple)

リスト

タプル

# [1;2;3];;- : int list = [1; 2; 3]# [1;2;3];;- : int list = [1; 2; 3]

# (1,2,3);;- : int * int * int = (1, 2, 3)# (1,2,3);;- : int * int * int = (1, 2, 3)

;で区切る

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

20

リストのつくりかた[1;2;3] と書くほかにも…

# 1::2::3::[];;- : int list = [1; 2; 3]# 1::2::3::[];;- : int list = [1; 2; 3]

# 1::[2;3];;- : int list = [1; 2; 3]# 1::[2;3];;- : int list = [1; 2; 3]

要素とリストをコロン二つで連結

[] は空リスト

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

21

レコード型

# 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"}

# 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” を定義“rt” はメンバー“a”,”b” を持つ

“rt” 型の変数“ rv” が定義された

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

22

ヴァリアント型

# type vt = Apple | Banana | Orange;;type vt = Apple | Banana | Orange

# let vv = Apple;;val vv : vt = Apple

# type vt = Apple | Banana | Orange;;type vt = Apple | Banana | Orange

# let vv = Apple;;val vv : vt = Apple

“ C の enum” 的な使い方

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

23

ヴァリアント型(2)

# 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

# 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

値つきのヴァリアント型を定義

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

24

パターンマッチング

let rec factorial = function | 1 -> 1 | n -> factorial (n - 1) * n

整数値に対するパターンマッチの例

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

25

パターンマッチング (2)

let rec pp_list = function | [] -> "" | [x] -> x | x :: xs -> x ^ " " ^ pp_list xs

# pp_list;;- : string list -> string = <fun># pp_list [“str1”;”str2”;”str3”];;- : string = “str1 str2 str3”

# pp_list;;- : string list -> string = <fun># pp_list [“str1”;”str2”;”str3”];;- : string = “str1 str2 str3”

リストに対するパターンマッチの例“Pretty Print List” - 「文字列のリスト」を「文字列」へ変換

^ は文字列の連結x はリストの先頭xs はリストの残り

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

26

パターンマッチング (3)ヴァリアントに対するパターンマッチの例

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)

UnSafe はサニタイズされていない HTML 文字列Safe はサニタイズ済みの HTML 文字列 ( のつもり )

二つの引数に対するパターンマッチング

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

27

モジュール

module Trig PI = 3.141592654 def Trig.sin(x) # .. end def Trig.cos(x) # .. endend

module Trig = struct let pi = 3.141592654 let sin x = ... let cos x = ... end

# Trig.cos 0.0;;- : float = 1.

# Trig.cos 0.0;;- : float = 1.

Ruby: OCaml:

Trig.cos(0)=> 1.0

Trig.cos(0)=> 1.0

『超』乱暴な説明:

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

28

標準ライブラリ

List モジュールが特によく使われるのでとりあえず紹介:

名前の通りリスト関連の関数が定義されている

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

29

List.map

Ruby の“ collect” イテレータと『ほぼ』同じ (?)

# List.map (fun x -> x + 1) [1;2;3];;- : int list = [2; 3; 4]# List.map (fun x -> x + 1) [1;2;3];;- : int list = [2; 3; 4]

[1,2,3].collect {|x| x + 1}=> [2, 3, 4]

Ruby:

OCaml:

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

30

List.fold_left

Ruby の“ inject” イテレータと『ほぼ』同じ (?)

# List.fold_left (fun sum element -> sum + element) 0 [1;2;3];;- : int = 6

# List.fold_left (fun sum element -> sum + element) 0 [1;2;3];;- : int = 6

[1,2,3].inject(0) {|sum, element| sum + element}=> 6

OCaml:

Ruby:

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

31

命令型処理

# let counter = ref 0 ;;val counter : int ref = {contents = 0}# let count () = counter := !counter + 1; !counter ;;

# let counter = ref 0 ;;val counter : int ref = {contents = 0}# let count () = counter := !counter + 1; !counter ;;

“ref” で代入可能な変数(参照型変数)を定義

# count ();;- : int = 1# count ();;- : int = 2

# count ();;- : int = 1# count ();;- : int = 2

• := で代入 (let が無いことに注意 )• ! を付けると参照型変数の 実際の値が得られる

; でつなげることにより複数の式を順に評価

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

32

他にもいろいろありますが…

あとは実践あるのみ。MinCaml のソースコードを

読みに行きましょう。

ということで一旦お開き