Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ocamllec01-100605110859-phpapp01.pdf

Avatar for Tomofumi Hayashi Tomofumi Hayashi
June 05, 2010
9

 ocamllec01-100605110859-phpapp01.pdf

Avatar for Tomofumi Hayashi

Tomofumi Hayashi

June 05, 2010
Tweet

Transcript

  1. Ocaml Objective Caml とは • Objective Caml = Caml言語のObject拡張版 •

    CamlとはフランスのINRIAという研究所で開発 された関数型言語で↓等々を供えた言語 – 型システム(型推論・多相型) – パターンマッチング • Ocamlはそれに↓を追加した言語 – モジュールシステム – オブジェクト機能 – Native Compiler (ネイティブバイナリ吐ける!)
  2. 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
  3. 目次 • インストール • “Hello world!” – プログラムの起動・終了 – プログラムの解説

    – その他 – 型について • 関数 – 関数定義 – 条件分岐 – 再帰 • データ構造体 – リスト・ペア – レコード – バリアント • パターンマッチ – 再帰 • 多相型について – 多相型関数 – 多相型データ
  4. インストール • Windows: Cygwin/MinGW/MSのどちからを選 択. – 違いはビルド環境 – ライブラリ,生成コードのインターフェイスに違い –

    詳しくは公式ページ (http://caml.inria.fr/ocaml/portability.en.html) – ちなみに僕はMinGWをよくインストールします – Tcl/Tk(Active TCL)をインストールすると吉 • Object Browser(リファレンス)が使えます – OcamlベースのF#をインストールするというのも…
  5. インストール • Mac: – Intel版を公式サイトからダウンロード – MacPortsからインストール • Unix/Linux: –

    ソースから頑張る • gccインストールよりは確実に楽です – パッケージはいろいろあります • Gentoo/Redhat/Debian for Linux • Ports/pkgsrc for *BSD
  6. 解説 kagaribi% ocaml Objective Caml version 3.10.2 # print_string "hello

    world!";; hello world!- : unit = () # ^D kagaribi% プログラムの入力 ”^d”で終了 出力 プログラムの型 プロンプト
  7. プログラム解説 # print_string “hello world!” ;; 関数名 引数 ターミネーター •

    引数渡す際にかっこ”()”やコンマ”,”は不要 • 文字列は””で囲む • プログラムを評価したい場合には”;;”を末尾に • 評価については2枚後で説明 • print_string は文字列を受けとって表示する関数
  8. “評価”とは? • 与えられたOcaml式をコンピュータが解析すること • 関数に全ての引数が与えられたら実行 kagaribi% ocaml Objective Caml version

    3.10.2 # print_string “test string”;; ←関数に引数を加えて評価 test string- : unit = () ←実行される # 10;; ←数字を評価 -: int = 10 ←評価の結果は変わらず # print_string;; ←関数を評価すると? - : string -> unit = <fun> ←関数が返ってくる #
  9. Type, Type, Type!!! (1) • 型推論する関数型言語にとって型は命です int : 31bit整数型 (Int32,

    Int64という型もあります) float : 不動小数点型 (doubleっぽい) string : 文字列型 (“test” で表記) char : 文字型 (‘a’ で表記) bool : true/false unit : 値を返さない型.値は()のみ T1 ->T2: 型T1の値を引数でT2の型の値を返す関数の型
  10. 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>
  11. 目次 • インストール • “Hello world!” – プログラムの起動・終了 – プログラムの解説

    – その他 – 型について • 関数 – 関数定義 – 条件分岐 – 再帰 • データ構造体 – リスト・ペア – レコード – バリアント • パターンマッチ – 再帰 • 多相型について – 多相型関数 – 多相型データ
  12. 関数/条件分岐 • 変数の定義・関数の定義 let foobar = 10;; let foobar =

    15 and 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している) 引数の型は明示的にも宣言可
  13. 関数/条件分岐 • 条件分岐 let testFunc a b = if (a

    > b) then a else b • If 式自身も値を返す構文であることに注目 – そのためにelseは必須
  14. 関数/条件分岐 • 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
  15. 繰り返し • 繰り返しは再帰で書く.これ,最強. – コンパイラが最適化しやすい • 再帰する場合は”let” -> “let rec”で書きます

    let rec testFun a = if (a < 1) then 0 else a + testFun (a-1) • しかし再帰ってスタックオーバーフローするんじゃ…? ↑ > 末尾再帰(tail recursion)すれば大丈夫です
  16. 末尾再帰(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 b else testFun (a-1) (b+a) # testFun 1000000000;; - : int = 5000000050000000 非末尾再帰で一億 末尾再帰で十億
  17. 目次 • インストール • “Hello world!” – プログラムの起動・終了 – プログラムの解説

    – その他 – 型について • 関数 – 関数定義 – 条件分岐 – 再帰 • データ構造体 – リスト・ペア – レコード – バリアント • パターンマッチ • 多相型について – 多相型関数 – 多相型データ
  18. リスト • 関数型言語ではリスト(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の連結には “::”を使用 •リスト操作については解説しませんが一回再帰で書いておくと吉 ↑これも関数型言語共通のマナーです(リスト&再帰脳)
  19. ペア • 複数の型を組み合わせたペアの構造体 • 要素に名前はつかない # (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)
  20. レコード • 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 = 10 val l : int = 20 レコード定義c 書けば型は推論 取るときは”.”を 使って こうやってもOK
  21. バリアント • 関数型言語ならではの構造体 • イメージとしては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) 非常にシンプル!
  22. バリアント # 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
  23. パターンマッチ let foobarToStr = function Void -> "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 文字列の結合: ^
  24. パターンマッチ • パターンマッチの方法は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 = 10 val b : int = 20 # let p = (10,20);; val p : int * int = (10, 20) # let (a, b) = p;; val a : int = 10 val b : int = 20 # let (a, _) = p;; val a : int = 10 # しかしやや強引 単に値を取る場合 ペア等には有効 “_”で値を無視
  25. パターンマッチ # 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が無視
  26. 多相型データ・関数 # 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> どんな型のリスト も対応する関数
  27. 多相型データ・関数 # 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
  28. お勧めリンク • 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”という本は駄目らしいです