Top Banner
OCaml勉強会@axsh (はじめのいっぽ) Id:s1061123
42

Ocaml lecture slides 01 at axsh

Jul 17, 2015

Download

Technology

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Ocaml lecture slides 01 at axsh

OCaml勉強会@axsh(はじめのいっぽ)

Id:s1061123

Page 2: Ocaml lecture slides 01 at axsh

Ocamlとは

• Ocaml = Objective Camlの略

Page 3: Ocaml lecture slides 01 at axsh
Page 4: Ocaml lecture slides 01 at axsh

公式ページにOcamlって書いてない!!!

公式ページはhttp://caml.inria.fr/index.en.htmlです.

Page 5: Ocaml lecture slides 01 at axsh

Objective Caml勉強会@axsh(はじめのいっぽ)

Id:s1061123

Page 6: Ocaml lecture slides 01 at axsh

Ocaml Objective Caml とは

• Objective Caml = Caml言語のObject拡張版

• CamlとはフランスのINRIAという研究所で開発された関数型言語で↓等々を供えた言語

– 型システム(型推論・多相型)

– パターンマッチング

• Ocamlはそれに↓を追加した言語

– モジュールシステム

– オブジェクト機能

– Native Compiler (ネイティブバイナリ吐ける!)

Page 7: Ocaml lecture slides 01 at axsh

Objective Camlの親戚一覧

• ML系列 (Objective Camlと同類)– F# (for .Net) http://research.microsoft.com/en-

us/um/cambridge/projects/fsharp/default.aspx

– Standard ML of New Jersey (SML/nj) http://www.smlnj.org/

– Alice http://www.ps.uni-saarland.de/alice/

– SML# http://www.pllab.riec.tohoku.ac.jp/smlsharp/ja/

• Haskell

• Closure

• Concurrent Clean

• Lisp/scheme

Page 8: Ocaml lecture slides 01 at axsh

特徴

• 型推論があるので(ある程度)プログラムのエラーを静的に解析できる

• パターンマッチによって複雑な条件式が簡潔に書ける

• 高階関数(Higher Order Function)や多相型(Polymorphic Type)によってより柔軟な処理の記述が可能

Page 9: Ocaml lecture slides 01 at axsh

最終的なGoal

• Ocamlのプログラムのコンパイルの仕方,実行方法が分かるようになる

• 関数型言語の知識が(少し)分かるようになる (型推論とか,パターンマッチングとか…)

• 関数型言語っぽいプログラミングのマナーを知る(再帰脳・リスト指向・高階関数使用)

Page 10: Ocaml lecture slides 01 at axsh

目次

• インストール

• “Hello world!”

– プログラムの起動・終了

– プログラムの解説

– その他

– 型について

• 関数

– 関数定義

– 条件分岐

– 再帰

• データ構造体

– リスト・ペア

– レコード

– バリアント

• パターンマッチ

– 再帰

• 多相型について

– 多相型関数

– 多相型データ

Page 11: Ocaml lecture slides 01 at axsh

インストール

• Windows: Cygwin/MinGW/MSのどちからを選択.

– 違いはビルド環境

– ライブラリ,生成コードのインターフェイスに違い

– 詳しくは公式ページ(http://caml.inria.fr/ocaml/portability.en.html)

– ちなみに僕はMinGWをよくインストールします

– Tcl/Tk(Active TCL)をインストールすると吉

• Object Browser(リファレンス)が使えます

ベースの をインストールするという

Page 12: Ocaml lecture slides 01 at axsh

インストール

• Mac:– Intel版を公式サイトからダウンロード

– MacPortsからインストール

• Unix/Linux:– ソースから頑張る

• gccインストールよりは確実に楽です

– パッケージはいろいろあります• Gentoo/Redhat/Debian for Linux

• Ports/pkgsrc for *BSD

Page 13: Ocaml lecture slides 01 at axsh

とりあえずhello world!

Windowsで

Unixで

Nativeバイナリ版はあとで解説しまつ

Page 14: Ocaml lecture slides 01 at axsh

解説

kagaribi% ocamlObjective Caml version 3.10.2

# print_string "hello world!";;hello world!- : unit = ()# ^Dkagaribi%

プログラムの入力

”^d”で終了

出力プログラムの

プロンプト

Page 15: Ocaml lecture slides 01 at axsh

プログラム解説

# print_string “hello world!” ;;

関数名 引数 ターミネーター

• 引数渡す際にかっこ”()”やコンマ”,”は不要

• 文字列は””で囲む

• プログラムを評価したい場合には”;;”を末尾に

• 評価については2枚後で説明

• print_string は文字列を受けとって表示する関数

Page 16: Ocaml lecture slides 01 at axsh

プログラム解説

• Print_stringの結果の表示の後に評価の結果を表示

• unitというのは型の一つでvoidみたいなもの

– 型についてはあとで説明

• “()”はunit型の値

• 他の例

hello world! - : unit = ()

標準出力 プロンプト結果の型 返り値

# 10 + 20;;- : int = 30#

Page 17: Ocaml lecture slides 01 at axsh

“評価”とは?

• 与えられたOcaml式をコンピュータが解析すること

• 関数に全ての引数が与えられたら実行

kagaribi% ocamlObjective Caml version 3.10.2

# print_string “test string”;; ←関数に引数を加えて評価test string- : unit = () ←実行される# 10;; ←数字を評価-: int = 10 ←評価の結果は変わらず# print_string;; ←関数を評価すると?- : string -> unit = <fun> ←関数が返ってくる#

Page 18: Ocaml lecture slides 01 at axsh

Type, Type, Type!!! (1)

• 型推論する関数型言語にとって型は命ですint : 31bit整数型 (Int32, Int64という型もあります)float : 不動小数点型 (doubleっぽい)string : 文字列型 (“test” で表記)char : 文字型 (‘a’ で表記)bool : true/falseunit : 値を返さない型.値は()のみT1 ->T2: 型T1の値を引数でT2の型の値を返す関数の型

Page 19: Ocaml lecture slides 01 at axsh

Type, Type, Type!!! (2): 例

kagaribi% ocaml

Objective Caml version 3.10.2

# 10;;

- : int = 10

# 10.1;;

- : float = 10.1

# "test";;

- : string = "test"

# 'a';;

- : char = 'a'

# true;;

- : bool = true

# false;;

- : bool = false

# ();;

- : unit = ()

# print_string;;

- : string -> unit = <fun>

Page 20: Ocaml lecture slides 01 at axsh

目次

• インストール

• “Hello world!”

– プログラムの起動・終了

– プログラムの解説

– その他

– 型について

• 関数

– 関数定義

– 条件分岐

– 再帰

• データ構造体

– リスト・ペア

– レコード

– バリアント

• パターンマッチ

– 再帰

• 多相型について

– 多相型関数

– 多相型データ

Page 21: Ocaml lecture slides 01 at axsh

関数/条件分岐• 変数の定義・関数の定義

let foobar = 10;;let foobar = 15and foobar2 = 20;;

let testfunc a = print_string “answer is “;print_int (a + 30) ;;

let testfunc a b = a + b;;let testfun a:int = a;;

• スコープ付き変数・関数の定義let foobar = 10 in foobar + 10 ;;

• 名前無し関数(closure)定義fun a -> a + 10;;

let testfunc a b = a + b;; ===== let testfunc = fun a b -> a + b;;

連続した命令は”;”で分ける

これは再代入とは違うので注意!!(新規に領域を作って名前をbindしてい

る)

引数の型は明示的にも宣言可

Page 22: Ocaml lecture slides 01 at axsh

関数/条件分岐

• 条件分岐

let testFunc a b =

if (a > b) then

a

else

b

• If 式自身も値を返す構文であることに注目

– そのためにelseは必須

Page 23: Ocaml lecture slides 01 at axsh

関数/条件分岐

• If節の中に複数の命令を入れる場合は注意が必要

• 条件分岐

let testFunc a b =

if (a > b) then

(print_string “a > b”; a)

else

(print_string “a =< b”; b)

• 括弧の中を左から評価して最後の値を返す– 注意:最後以外はunitを返さないとwarning

• ()の代わりにbegin … endでもOK

Page 24: Ocaml lecture slides 01 at axsh

繰り返し命令

• While/forはありますがそれを使うのは

Page 25: Ocaml lecture slides 01 at axsh

繰り返し

• 繰り返しは再帰で書く.これ,最強.

– コンパイラが最適化しやすい

• 再帰する場合は”let” -> “let rec”で書きます

let rec testFun a =

if (a < 1) then

0

else

a + testFun (a-1)

• しかし再帰ってスタックオーバーフローするんじゃ…?

↑ > 末尾再帰(tail recursion)すれば大丈夫です

Page 26: Ocaml lecture slides 01 at axsh

末尾再帰(tail recursion)の勧め

• 末尾再帰とは再帰の一種で再帰呼出以降に命令が存在しない再帰の呼び方

• イメージ的には再帰で返ってくる時に値を返す以外のことをしないような再帰

• この場合スタックは呼ばれた回数に比例して増大

A = 10 A = 0 A = 10

let rec testFun a = if (a < 1) then

0 else

a + testFun (a-1)

1+0 2+1 3+3 10+45 = 55

非末尾再帰

Page 27: Ocaml lecture slides 01 at axsh

末尾再帰(tail recursion)の勧め

• 関数型言語の場合,末尾再帰の呼出し最適化によって再帰呼びだしは最適化されてジャンプ命令になる→スタック使わない

• よってスタックの増減は再帰回数に依存して増加しない

• 返すべき値を引数に渡すと案外簡単に末尾再帰に

A = 10 A = 0 A = 10

let testFunc a = let rec testFun1 a b =

if (a < 1) then b

else testFun1 (a-1) (b+a)

in testFun1 a 0

末尾再帰!

testFun1 10 0

testFun1 10 0testFun1 9 10testFun1 8 19…testFun1 0 55

testFun1 0 55 55

Page 28: Ocaml lecture slides 01 at axsh

末尾再帰(tail recursion)の勧め

• 末尾再帰を思い付く(→再帰脳)は関数型言語の壁の一つ

• OcamlだけではなくHaskell, Closureでも使えるスキルなので是非!

let rec testFun a = if (a < 1) then

0 else a + testFun (a-1)# testFun 100000000;;Stack overflow during evaluation (looping recursion?).

let rec testFun a b = if (a < 1) then

belse

testFun (a-1) (b+a)# testFun 1000000000;;- : int = 5000000050000000

非末尾再帰で一億

末尾再帰で十億

Page 29: Ocaml lecture slides 01 at axsh

このあたりで休憩とか

Page 30: Ocaml lecture slides 01 at axsh

目次

• インストール

• “Hello world!”

– プログラムの起動・終了

– プログラムの解説

– その他

– 型について

• 関数

– 関数定義

– 条件分岐

– 再帰

• データ構造体

– リスト・ペア

– レコード

– バリアント

• パターンマッチ

• 多相型について

– 多相型関数

– 多相型データ

Page 31: Ocaml lecture slides 01 at axsh

リスト

• 関数型言語ではリスト(linked list)を基本データとして扱っています

# [10; 20; 30];;-: int list = [10; 20; 30]

# 10 :: [20; 30];;-: int list = [10; 20; 30]

# 10 :: (20 :: [30]);;-: int list = [10; 20; 30]

# 10 :: (20 :: (30 :: []));;- : int list = [10; 20; 30]#

10 20 30

car cdr

•リストは先頭の要素(car)と後続のリスト(cdr)で構成• []で空リストを表現•car と cdrの連結には “::”を使用

•リスト操作については解説しませんが一回再帰で書いておくと吉↑これも関数型言語共通のマナーです(リスト&再帰脳)

Page 32: Ocaml lecture slides 01 at axsh

ペア

• 複数の型を組み合わせたペアの構造体

• 要素に名前はつかない

# (10, 20);;-: int * int = (10, 20)

# (10, 10.200);;-: int * float = (10, 10.2)

# (10, "teststr", 30.2);;-: int * string * float = (10, "teststr", 30.2)

# let pair = (10, "teststr", 30.2);;val pair : int * string * float = (10, "teststr", 30.2)

Page 33: Ocaml lecture slides 01 at axsh

レコード

• C言語でいう構造体

# type pair_of_ints = { a : int; b : int; };;type pair_of_ints = { a : int; b : int; }

# {a = 10; b = 20};;- : pair_of_ints = {a = 10; b = 20}

# let p = {a = 10; b = 20};;val p : pair_of_ints = {a = 10; b = 20}# p.a;;- : int = 10

# let {a=k; b=l} = p;;val k : int = 10val l : int = 20

レコード定義c

書けば型は推論

取るときは”.”を使って

こうやってもOK

Page 34: Ocaml lecture slides 01 at axsh

バリアント

• 関数型言語ならではの構造体

• イメージとしてはCのenum + union

typedef struct foobar_ { enum type_ {TEST_VOID,TEST_INT,TEST_FLOAT,TEST_CHAR } type;

union { int i;float d;char c;

} val;} foobar;

# type foobar = Void | Int of int | Float of float | Char of char | Pair of (int * int);; type foobar =

Void| Int of int| Float of float| Char of string| Pair of (int * int)

非常にシンプル!

Page 35: Ocaml lecture slides 01 at axsh

バリアント# type foobar = Void | Int of int | Float of float | Char of string | Pair of (int * int);; type foobar =

Void| Int of int| Float of float| Char of string| Pair of (int * int)

# Void;;- : foobar = Void# Int 20;;- : foobar = Int 20# Pair (20, 20);;- : foobar = Pair (20, 20)

# None;;- : 'a option = None# Some 10;;- : int option = Some 10

使用例: option

Page 36: Ocaml lecture slides 01 at axsh

パターンマッチ

let foobarToStr = functionVoid -> "void"

| Int i -> "Int(" ^ (string_of_int i) ^ ")"| Float f -> "Float(" ^ (string_of_float f) ^ ")"| Char c -> "Char(" ^ c ^ ")"| Pair (a, b) -> "Pair(" ^ (string_of_int a) ^ ", " ^ (string_of_int b) ^ ")";;

val foobarToStr : foobar -> string = <fun>

• データのパターン(型の構造)で条件分岐が可能!

# foobarToStr Pair(10,20);;This function is applied to too many arguments,maybe you forgot a `;'

# foobarToStr (Pair(10,20));;- : string = "Pair(10, 20)"

# foobarToStr Void;;- : string = "void"

int -> stringの変換:string_of_int文字列の結合: ^

Page 37: Ocaml lecture slides 01 at axsh

パターンマッチ

• パターンマッチの方法は3種類# let p = Pair(10,20);;val p : foobar = Pair (10, 20)# let Pair(a,b) = p;;Warning P: this pattern-matching is not exhaustive.Here is an example of a value that is not matched:(Char _|Float _|Int _|Void)val a : int = 10val b : int = 20

# let p = (10,20);;val p : int * int = (10, 20)# let (a, b) = p;;val a : int = 10val b : int = 20# let (a, _) = p;;val a : int = 10#

しかしやや強引

単に値を取る場合

ペア等には有効

“_”で値を無視

Page 38: Ocaml lecture slides 01 at axsh

パターンマッチ

# let foobarToStr a =match a with

Void -> "Void"| Int a when a > 100 -> "BigInt"| Int _ -> "Int"| _ -> "Others";;

val foobarToStr : foobar -> string = <fun>

# foobarToStr (Int 10);;- : string = "Int"# foobarToStr (Int 200);;- : string = "BigInt"

# let foob# let foobarToStr a =match a with

Void -> "Void"| Int _ -> "Int"| Int a when a > 100 -> "BigInt"| _ -> "Others";;

Warning U: this match case is unused.val foobarToStr : foobar -> string = <fun># foobarToStr (Int 200);;- : string = "Int"

When で条件追加

比較は上から順番なのでこの場合

BigIntが無視

Page 39: Ocaml lecture slides 01 at axsh

多相型データ・関数

# let getRight (_, a) = a;;val getRight : 'a * 'b -> 'b = <fun>

ペアの右を返す関数

‘a , ‘b : “型”の変数で’どんな型が来ても構わない’ということ.‘a と’bが同じでも構わない.ただし一回目の’bと二回目の’bは同じ

# let getHead (h::t) = h;;Warning P: this pattern-matching is not exhaustive.Here is an example of a value that is not matched:[]val getHead : 'a list -> 'a = <fun># let getHead l = match l with (h::t) -> Some h | [] -> None;;val getHead : 'a list -> 'a option = <fun>

どんな型のリストも対応する関

Page 40: Ocaml lecture slides 01 at axsh

多相型データ・関数

# type 'a pairs = { a : 'a ; b : int; };;type 'a pairs = { a : 'a; b : int; }

# type 'a tree = None | Node of ('a * 'a tree * 'a tree);;type 'a tree = None | Node of ('a * 'a tree * 'a tree)

# Node(10, Node(20, None, None), Node(30, None, None));;- : int tree = Node (10, Node (20, None, None), Node (30, None, None))#

多相型レコード

多相型バリアントで

バイナリツリー

10

20 30

Page 41: Ocaml lecture slides 01 at axsh

次回予告

• 多相型関数

– 実際例(foldを用いて)

• 例外

• 参照

• モジュール

• オブジェクト

Page 42: Ocaml lecture slides 01 at axsh

お勧めリンク

• http://ocaml.jp/

• http://www.ocaml-tutorial.org/ja

マニア向けのリンク

• http://ocaml.janestreet.com/?q=node/13– (from http://d.hatena.ne.jp/camlspotter/20090906 )

• 余談:“Practical OCaml”という本は駄目らしいです