(Rubyist のための ) 超音速: ML 入門
description
Transcript of (Rubyist のための ) 超音速: ML 入門
1
(Rubyist のための )超音速: ML 入門
福盛秀雄http://fukumori.org
Ver.2005.07.30
2
準備運動
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 3.08.3
#
$ ocaml Objective Caml version 3.08.3
#
6
ふつ~の計算
# 123 + 456;;- : int = 579# 123 + 456;;- : int = 579
コロン二つで式の評価
結果の表示
7
ふつ~の計算 !?
# 123.0 +. 456.0;;- : float = 579.# 123.0 +. 456.0;;- : float = 579.
普通じゃないよ!
浮動小数点の足し算は +.
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
んなものは無い。浮動小数点演算と
整数演算を混ぜてみる
(当然のように)エラーとなる
9
これなら OK
# 123.0 +. float_of_int 456;;- : float = 579.# 123.0 +. float_of_int 456;;- : float = 579.
int -> float の関数
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 < 変数名 > = ... で定義
定義された変数の型が表示される
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” が定義された
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 を返す関数」
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 を束縛
本質的には両者の間に明確な区別はない(?)。関数を別の変数に束縛したり、別の関数の引数にしたりすることもできる
14
無名関数
{|x| x + 1}
名前の通り「名前の無い関数」Ruby のブロックに似ていないこともない
fun x -> x + 1
ちなみに OCaml にてlet f x = x + 1 とlet f = fun x -> x + 1 は等価
Ruby:
OCaml:
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”というエラーとなる
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
17
関数型言語の特徴 (2)
•ループは書けない(書かない) →再帰を使う•変数は変更できない →計算の途中経過は引数と 返り値に入れておく
•変数は immutable→ 代入はできない•関数は同じ引数に対して必ず同じ値を返す
18
関数型言語の特徴 (3)
値の定義:強力なデータ型値の参照:強力なパターンマッチング
「計算の途中経過は引数と 返り値に入れておく」
どうやって実現?
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)
;で区切る
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]
要素とリストをコロン二つで連結
[] は空リスト
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” が定義された
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” 的な使い方
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
値つきのヴァリアント型を定義
24
パターンマッチング
let rec factorial = function | 1 -> 1 | n -> factorial (n - 1) * n
整数値に対するパターンマッチの例
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 はリストの残り
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 文字列 ( のつもり )
二つの引数に対するパターンマッチング
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
『超』乱暴な説明:
28
標準ライブラリ
List モジュールが特によく使われるのでとりあえず紹介:
名前の通りリスト関連の関数が定義されている
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:
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:
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 が無いことに注意 )• ! を付けると参照型変数の 実際の値が得られる
; でつなげることにより複数の式を順に評価
32
他にもいろいろありますが…
あとは実践あるのみ。MinCaml のソースコードを
読みに行きましょう。
ということで一旦お開き