トップ
新規
単語検索
ヘルプ
The core Chapter 1 The core languagelanguage
をテンプレートにして作成
開始行:
*Chapter 1 The core language [#k53c59c2]
本章は Objective Caml のチュートリアルです。手続き型言語 ...
**1.1 Basics [#obbe890d]
ここでは、OCaml の対話式システムを使用して Caml の概要を...
対話式システムでは、ユーザの入力文が ;; で区切られます。...
#1+2*3;;
- : int = 7
#let pi = 4.0 *. atan 1.0;;
val pi : float = 3.14159265359
#let square x = x *. x;;
val square : float -> float = <fun>
#square(sin pi) +. square(cos pi);;
- : float = 1.
Caml システムはそれぞれの文に対して値と型の両方を計算する...
#1.0 * 2;;
This expression has type float but is here used with typ...
再帰的な関数は let rec で定義します。
#let rec fib n =
if n < 2 then 1 else fib(n-1) + fib(n-2);;
val fib : int -> int = <fun>
#fib 10;;
- : int = 89
**1.2 Data types [#i3ecc9fe]
整数と浮動小数以外に、Caml には boolean 、文字 (character...
#(1 < 2) = false;;
- : bool = false
#'a';;
- : char = 'a'
#"Hello world";;
- : string = "Hello world"
あらかじめ定義されているデータ構造として、組 (tuple) 、配...
#let l = ["is"; "a"; "tale"; "told"; "etc."];;
val l : string list = ["is"; "a"; "tale"; "told"; "etc."]
#"Life" :: l;;
- : string list = ["Life"; "is"; "a"; "tale"; "told"; "e...
リストは明示的にメモリを確保、開放する必要はありません。...
リストの中を見たり解体したりするためにはパターンマッチン...
#let rec sort lst =
match lst with
[] -> []
| head :: tail -> insert head (sort tail)
and insert elt lst =
match lst with
[] -> [elt]
| head :: tail -> if elt <= head then elt :: lst else...
;;
val sort : 'a list -> 'a list = <fun>
val insert : 'a -> 'a list -> 'a list = <fun>
#sort l;;
- : string list = ["a"; "etc."; "is"; "tale"; "told"]
sort の型は 'a list -> 'a list と推論されます。つまり sor...
#sort [6;2;5;3];;
- : int list = [2; 3; 5; 6]
#sort [3.14; 2.718];;
- : float list = [2.718; 3.14]
上の sort 関数は入力されたリストを書き換えません。入力さ...
**1.3 Functions as values [#x9a479c6]
Caml は関数型言語です。当然数学的な意味の関数としても使え...
#let deriv f dx = function x -> (f(x +. dx) -. f(x)) /. ...
val deriv : (float -> float) -> float -> float -> float ...
#let sin' = deriv sin 1e-6;;
val sin' : float -> float = <fun>
#sin' pi;;
- : float = -1.00000000014
関数の合成も定義出来ます。
#let compose f g = function x -> f(g(x));;
val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>
#let cos2 = compose square cos;;
val cos2 : float -> float = <fun>
関数の引数として渡された関数は ``functionals'' や ``高階...
#List.map (function n -> n * 2 + 1) [0;1;2;3;4];;
- : int list = [1; 3; 5; 7; 9]
この高階関数などのように、リストや配列を処理する高階関数...
#let rec map f l =
match l with
[] -> []
| hd :: tl -> f hd :: map f tl;;
val map : ('a -> 'b) -> 'a list -> 'b list = <fun>
**1.4 Records and variants [#nd89a729]
ユーザ定義データ構造にはレコード (record) とバリアント (v...
#type ratio = {num: int; denum: int};;
type ratio = { num : int; denum : int; }
#let add_ratio r1 r2 =
{num = r1.num * r2.denum + r2.num * r1.denum;
denum = r1.denum * r2.denum};;
val add_ratio : ratio -> ratio -> ratio = <fun>
#add_ratio {num=1; denum=3} {num=2; denum=5};;
- : ratio = {num = 11; denum = 15}
バリアント型の宣言は、その型の値が取りうる形を全て並べ立...
#type number = Int of int | Float of float | Error;;
type number = Int of int | Float of float | Error
この宣言は number 型が、整数か浮動小数か (0 除算などの) ...
バリアント型の特殊な場合として、すべてが定数であるものが...
#type sign = Positive | Negative;;
type sign = Positive | Negative
#let sign_int n = if n >= 0 then Positive else Negative;;
val sign_int : int -> sign = <fun>
number 型の算術演算を定義するには、2 つの number 型値に対...
#let add_num n1 n2 =
match (n1, n2) with
(Int i1, Int i2) ->
(* Check for overflow of integer addition *)
if sign_int i1 = sign_int i2 && sign_int(i1 + i2)...
then Float(float i1 +. float i2)
else Int(i1 + i2)
| (Int i1, Float f2) -> Float(float i1 +. f2)
| (Float f1, Int i2) -> Float(f1 +. float i2)
| (Float f1, Float f2) -> Float(f1 +. f2)
| (Error, _) -> Error
| (_, Error) -> Error;;
val add_num : number -> number -> number = <fun>
#add_num (Int 123) (Float 3.14159);;
- : number = Float 126.14159
バリアント型の主な用途は再帰的なデータ構造の記述です。2 ...
#type 'a btree = Empty | Node of 'a * 'a btree * 'a btre...
type 'a btree = Empty | Node of 'a * 'a btree * 'a btree
これは、'a (型は自由) 型の値を持つ 2 分木は、空 (Empty) ...
2 分木の処理は、データ構造の型定義に従うような再帰関数で...
#let rec member x btree =
match btree with
Empty -> false
| Node(y, left, right) ->
if x = y then true else
if x < y then member x left else member x right;;
val member : 'a -> 'a btree -> bool = <fun>
#let rec insert x btree =
match btree with
Empty -> Node(x, Empty, Empty)
| Node(y, left, right) ->
if x <= y then Node(y, insert x left, right)
else Node(y, left, insert x right);;
val insert : 'a -> 'a btree -> 'a btree = <fun>
**1.5 Imperative features [#a65b5cb6]
今まではすべての例を純粋な関数型スタイルで書いてきました...
#let add_vect v1 v2 =
let len = min (Array.length v1) (Array.length v2) in
let res = Array.create len 0.0 in
for i = 0 to len - 1 do
res.(i) <- v1.(i) +. v2.(i)
done;
res;;
val add_vect : float array -> float array -> float array...
#add_vect [| 1.0; 2.0 |] [| 3.0; 4.0 |];;
- : float array = [|4.; 6.|]
レコード型の定義に mutable が宣言されているフィールドなら...
#type mutable_point = { mutable x: float; mutable y: flo...
type mutable_point = { mutable x : float; mutable y : fl...
#let translate p dx dy =
p.x <- p.x +. dx; p.y <- p.y +. dy;;
val translate : mutable_point -> float -> float -> unit ...
#let mypoint = { x = 0.0; y = 0.0 };;
val mypoint : mutable_point = {x = 0.; y = 0.}
#translate mypoint 1.0 2.0;;
- : unit = ()
#mypoint;;
- : mutable_point = {x = 1.; y = 2.}
Caml には変数という概念が組み込まれていません。ここで言う...
#let insertion_sort a =
for i = 1 to Array.length a - 1 do
let val_i = a.(i) in
let j = ref i in
while !j > 0 && val_i < a.(!j - 1) do
a.(!j) <- a.(!j - 1);
j := !j - 1
done;
a.(!j) <- val_i
done;;
val insertion_sort : 'a array -> unit = <fun>
次の呼び出しがあるまで現在の状態を保持しなければならない...
#let current_rand = ref 0;;
val current_rand : int ref = {contents = 0}
#let random () =
current_rand := !current_rand * 25713 + 1345;
!current_rand;;
val random : unit -> int = <fun>
再度説明しますが、参照は内部的に実現されているわけではあ...
#type 'a ref = { mutable contents: 'a };;
type 'a ref = { mutable contents : 'a; }
#let (!) r = r.contents;;
val ( ! ) : 'a ref -> 'a = <fun>
#let (:=) r newval = r.contents <- newval;;
val ( := ) : 'a ref -> 'a -> unit = <fun>
型多相な関数を、型多相のままデータ構造に保持しなくてはな...
#type idref = { mutable id: 'a. 'a -> 'a };;
type idref = { mutable id : 'a. 'a -> 'a; }
#let r = {id = fun x -> x};;
val r : idref = {id = <fun>}
#let g s = (s.id 1, s.id true);;
val g : idref -> int * bool = <fun>
#r.id <- (fun x -> print_string "called id\n"; x);;
- : unit = ()
#g r;;
called id
called id
- : int * bool = (1, true)
**1.6 Exceptions [#v16830f1]
Caml では例外状況を伝え、受け取るための例外機構が提供され...
#exception Empty_list;;
exception Empty_list
#let head l =
match l with
[] -> raise Empty_list
| hd :: tl -> hd;;
val head : 'a list -> 'a = <fun>
#head [1;2];;
- : int = 1
#head [];;
Exception: Empty_list.
標準ライブラリの関数は正常に処理を完了できなかったとき例...
#List.assoc 1 [(0, "zero"); (1, "one")];;
- : string = "one"
#List.assoc 2 [(0, "zero"); (1, "one")];;
Exception: Not_found.
例外は try...with でトラップすることが出来ます。
#let name_of_binary_digit digit =
try
List.assoc digit [0, "zero"; 1, "one"]
with Not_found ->
"not a binary digit";;
val name_of_binary_digit : int -> string = <fun>
#name_of_binary_digit 0;;
- : string = "zero"
#name_of_binary_digit (-1);;
- : string = "not a binary digit"
with の部分は、例外の値をパターンマッチングすることが出来...
#let temporarily_set_reference ref newval funct =
let oldval = !ref in
try
ref := newval;
let res = funct () in
ref := oldval;
res
with x ->
ref := oldval;
raise x;;
val temporarily_set_reference : 'a ref -> 'a -> (unit ->...
**1.7 Symbolic processing of expressions [#zc54ea13]
このチュートリアルの最後に、Caml の記号処理の使い方を代表...
#type expression =
Const of float
| Var of string
| Sum of expression * expression (* e1 + e2 *)
| Diff of expression * expression (* e1 - e2 *)
| Prod of expression * expression (* e1 * e2 *)
| Quot of expression * expression (* e1 / e2 *)
;;
type expression =
Const of float
| Var of string
| Sum of expression * expression
| Diff of expression * expression
| Prod of expression * expression
| Quot of expression * expression
変数名に値を割り当てた環境から、計算式を評価する関数を定...
#exception Unbound_variable of string;;
exception Unbound_variable of string
#let rec eval env exp =
match exp with
Const c -> c
| Var v ->
(try List.assoc v env with Not_found -> raise(Unb...
| Sum(f, g) -> eval env f +. eval env g
| Diff(f, g) -> eval env f -. eval env g
| Prod(f, g) -> eval env f *. eval env g
| Quot(f, g) -> eval env f /. eval env g;;
val eval : (string * float) list -> expression -> float ...
#eval [("x", 1.0); ("y", 3.14)] (Prod(Sum(Var "x", Const...
- : float = 9.42
本当の記号処理として、与えられた式の与えられた変数 dv で...
#let rec deriv exp dv =
match exp with
Const c -> Const 0.0
| Var v -> if v = dv then Const 1.0 else Const 0.0
| Sum(f, g) -> Sum(deriv f dv, deriv g dv)
| Diff(f, g) -> Diff(deriv f dv, deriv g dv)
| Prod(f, g) -> Sum(Prod(f, deriv g dv), Prod(deriv f...
| Quot(f, g) -> Quot(Diff(Prod(deriv f dv, g), Prod(f...
Prod(g, g))
;;
val deriv : expression -> string -> expression = <fun>
#deriv (Quot(Const 1.0, Var "x")) "x";;
- : expression =
Quot (Diff (Prod (Const 0., Var "x"), Prod (Const 1., Co...
Prod (Var "x", Var "x"))
**1.8 Pretty-printing and parsing [#na8dcc74]
上の例で示された例では、少し式が大きくなるだけで、式の内...
プリンタの関数が不要なカッコを表記しないで済むように、演...
#let print_expr exp =
(* Local function definitions *)
let open_paren prec op_prec =
if prec > op_prec then print_string "(" in
let close_paren prec op_prec =
if prec > op_prec then print_string ")" in
let rec print prec exp = (* prec is the current p...
match exp with
Const c -> print_float c
| Var v -> print_string v
| Sum(f, g) ->
open_paren prec 0;
print 0 f; print_string " + "; print 0 g;
close_paren prec 0
| Diff(f, g) ->
open_paren prec 0;
print 0 f; print_string " - "; print 1 g;
close_paren prec 0
| Prod(f, g) ->
open_paren prec 2;
print 2 f; print_string " * "; print 2 g;
close_paren prec 2
| Quot(f, g) ->
open_paren prec 2;
print 2 f; print_string " / "; print 3 g;
close_paren prec 2
in print 0 exp;;
val print_expr : expression -> unit = <fun>
#let e = Sum(Prod(Const 2.0, Var "x"), Const 1.0);;
val e : expression = Sum (Prod (Const 2., Var "x"), Cons...
#print_expr e; print_newline();;
2. * x + 1.
- : unit = ()
#print_expr (deriv e "x"); print_newline();;
2. * 1. + 0. * x + 0.
- : unit = ()
(具体文法から抽象文法に変換する) パージングは大抵プリント...
##load "camlp4o.cma";;
Camlp4 Parsing version 3.05 (2002-07-22)
#open Genlex;;
let lexer = make_lexer ["("; ")"; "+"; "-"; "*"; "/"];;
val lexer : char Stream.t -> Genlex.token Stream.t = <fun>
(与えられた文字列をトークンのストリームに変換する) 字句解...
#let token_stream = lexer(Stream.of_string "1.0 +x");;
val token_stream : Genlex.token Stream.t = <abstr>
#Stream.next token_stream;;
- : Genlex.token = Float 1.
#Stream.next token_stream;;
- : Genlex.token = Kwd "+"
#Stream.next token_stream;;
- : Genlex.token = Ident "x"
パージング自体はトークンのストリームをパターンマッチング...
対話式システムのトップレベルでストリームパーザを使用する...
##load"camlp4o.cma";;
Camlp4 Parsing version 3.05 (2002-07-22)
それからパーザを定義します。
#let rec parse_expr = parser
[< e1 = parse_mult; e = parse_more_adds e1 >] -> e
and parse_more_adds e1 = parser
[< 'Kwd "+"; e2 = parse_mult; e = parse_more_adds (...
| [< 'Kwd "-"; e2 = parse_mult; e = parse_more_adds (...
| [< >] -> e1
and parse_mult = parser
[< e1 = parse_simple; e = parse_more_mults e1 >] -> e
and parse_more_mults e1 = parser
[< 'Kwd "*"; e2 = parse_simple; e = parse_more_mult...
| [< 'Kwd "/"; e2 = parse_simple; e = parse_more_mult...
| [< >] -> e1
and parse_simple = parser
[< 'Ident s >] -> Var s
| [< 'Int i >] -> Const(float i)
| [< 'Float f >] -> Const f
| [< 'Kwd "("; e = parse_expr; 'Kwd ")" >] -> e;;
val parse_expr : Genlex.token Stream.t -> expression = <...
val parse_more_adds : expression -> Genlex.token Stream....
<fun>
val parse_mult : Genlex.token Stream.t -> expression = <...
val parse_more_mults : expression -> Genlex.token Stream...
<fun>
val parse_simple : Genlex.token Stream.t -> expression =...
#let parse_expression = parser [< e = parse_expr; _ = St...
val parse_expression : Genlex.token Stream.t -> expressi...
字句解析器と構文解析器を作成し、文字列から計算式を読む関...
#let read_expression s = parse_expression(lexer(Stream.o...
val read_expression : string -> expression = <fun>
#read_expression "2*(x+y)";;
- : expression = Prod (Const 2., Sum (Var "x", Var "y"))
ちょっとしたクイズです。なぜ以下の 2 つの例は結果が異なる...
#read_expression "x - 1";;
- : expression = Diff (Var "x", Const 1.)
#read_expression "x-1";;
Exception: Stream.Error "".
答えです。Genlex の字句解析器は負の整数を 1 つの整数とし...
**1.9 Standalone Caml programs [#lceb9c2e]
今までは対話式システムですべての例を実行してきました。Cam...
(* File fib.ml *)
let rec fib n =
if n < 2 then 1 else fib(n-1) + fib(n-2);;
let main () =
let arg = int_of_string Sys.argv.(1) in
print_int(fib arg);
print_newline();
exit 0;;
main ();;
Sys.argv はコマンドライン引数の文字列の配列です。Sys.argv...
$ ocamlc -o fib fib.ml
$ ./fib 10
89
$ ./fib 20
10946
終了行:
*Chapter 1 The core language [#k53c59c2]
本章は Objective Caml のチュートリアルです。手続き型言語 ...
**1.1 Basics [#obbe890d]
ここでは、OCaml の対話式システムを使用して Caml の概要を...
対話式システムでは、ユーザの入力文が ;; で区切られます。...
#1+2*3;;
- : int = 7
#let pi = 4.0 *. atan 1.0;;
val pi : float = 3.14159265359
#let square x = x *. x;;
val square : float -> float = <fun>
#square(sin pi) +. square(cos pi);;
- : float = 1.
Caml システムはそれぞれの文に対して値と型の両方を計算する...
#1.0 * 2;;
This expression has type float but is here used with typ...
再帰的な関数は let rec で定義します。
#let rec fib n =
if n < 2 then 1 else fib(n-1) + fib(n-2);;
val fib : int -> int = <fun>
#fib 10;;
- : int = 89
**1.2 Data types [#i3ecc9fe]
整数と浮動小数以外に、Caml には boolean 、文字 (character...
#(1 < 2) = false;;
- : bool = false
#'a';;
- : char = 'a'
#"Hello world";;
- : string = "Hello world"
あらかじめ定義されているデータ構造として、組 (tuple) 、配...
#let l = ["is"; "a"; "tale"; "told"; "etc."];;
val l : string list = ["is"; "a"; "tale"; "told"; "etc."]
#"Life" :: l;;
- : string list = ["Life"; "is"; "a"; "tale"; "told"; "e...
リストは明示的にメモリを確保、開放する必要はありません。...
リストの中を見たり解体したりするためにはパターンマッチン...
#let rec sort lst =
match lst with
[] -> []
| head :: tail -> insert head (sort tail)
and insert elt lst =
match lst with
[] -> [elt]
| head :: tail -> if elt <= head then elt :: lst else...
;;
val sort : 'a list -> 'a list = <fun>
val insert : 'a -> 'a list -> 'a list = <fun>
#sort l;;
- : string list = ["a"; "etc."; "is"; "tale"; "told"]
sort の型は 'a list -> 'a list と推論されます。つまり sor...
#sort [6;2;5;3];;
- : int list = [2; 3; 5; 6]
#sort [3.14; 2.718];;
- : float list = [2.718; 3.14]
上の sort 関数は入力されたリストを書き換えません。入力さ...
**1.3 Functions as values [#x9a479c6]
Caml は関数型言語です。当然数学的な意味の関数としても使え...
#let deriv f dx = function x -> (f(x +. dx) -. f(x)) /. ...
val deriv : (float -> float) -> float -> float -> float ...
#let sin' = deriv sin 1e-6;;
val sin' : float -> float = <fun>
#sin' pi;;
- : float = -1.00000000014
関数の合成も定義出来ます。
#let compose f g = function x -> f(g(x));;
val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>
#let cos2 = compose square cos;;
val cos2 : float -> float = <fun>
関数の引数として渡された関数は ``functionals'' や ``高階...
#List.map (function n -> n * 2 + 1) [0;1;2;3;4];;
- : int list = [1; 3; 5; 7; 9]
この高階関数などのように、リストや配列を処理する高階関数...
#let rec map f l =
match l with
[] -> []
| hd :: tl -> f hd :: map f tl;;
val map : ('a -> 'b) -> 'a list -> 'b list = <fun>
**1.4 Records and variants [#nd89a729]
ユーザ定義データ構造にはレコード (record) とバリアント (v...
#type ratio = {num: int; denum: int};;
type ratio = { num : int; denum : int; }
#let add_ratio r1 r2 =
{num = r1.num * r2.denum + r2.num * r1.denum;
denum = r1.denum * r2.denum};;
val add_ratio : ratio -> ratio -> ratio = <fun>
#add_ratio {num=1; denum=3} {num=2; denum=5};;
- : ratio = {num = 11; denum = 15}
バリアント型の宣言は、その型の値が取りうる形を全て並べ立...
#type number = Int of int | Float of float | Error;;
type number = Int of int | Float of float | Error
この宣言は number 型が、整数か浮動小数か (0 除算などの) ...
バリアント型の特殊な場合として、すべてが定数であるものが...
#type sign = Positive | Negative;;
type sign = Positive | Negative
#let sign_int n = if n >= 0 then Positive else Negative;;
val sign_int : int -> sign = <fun>
number 型の算術演算を定義するには、2 つの number 型値に対...
#let add_num n1 n2 =
match (n1, n2) with
(Int i1, Int i2) ->
(* Check for overflow of integer addition *)
if sign_int i1 = sign_int i2 && sign_int(i1 + i2)...
then Float(float i1 +. float i2)
else Int(i1 + i2)
| (Int i1, Float f2) -> Float(float i1 +. f2)
| (Float f1, Int i2) -> Float(f1 +. float i2)
| (Float f1, Float f2) -> Float(f1 +. f2)
| (Error, _) -> Error
| (_, Error) -> Error;;
val add_num : number -> number -> number = <fun>
#add_num (Int 123) (Float 3.14159);;
- : number = Float 126.14159
バリアント型の主な用途は再帰的なデータ構造の記述です。2 ...
#type 'a btree = Empty | Node of 'a * 'a btree * 'a btre...
type 'a btree = Empty | Node of 'a * 'a btree * 'a btree
これは、'a (型は自由) 型の値を持つ 2 分木は、空 (Empty) ...
2 分木の処理は、データ構造の型定義に従うような再帰関数で...
#let rec member x btree =
match btree with
Empty -> false
| Node(y, left, right) ->
if x = y then true else
if x < y then member x left else member x right;;
val member : 'a -> 'a btree -> bool = <fun>
#let rec insert x btree =
match btree with
Empty -> Node(x, Empty, Empty)
| Node(y, left, right) ->
if x <= y then Node(y, insert x left, right)
else Node(y, left, insert x right);;
val insert : 'a -> 'a btree -> 'a btree = <fun>
**1.5 Imperative features [#a65b5cb6]
今まではすべての例を純粋な関数型スタイルで書いてきました...
#let add_vect v1 v2 =
let len = min (Array.length v1) (Array.length v2) in
let res = Array.create len 0.0 in
for i = 0 to len - 1 do
res.(i) <- v1.(i) +. v2.(i)
done;
res;;
val add_vect : float array -> float array -> float array...
#add_vect [| 1.0; 2.0 |] [| 3.0; 4.0 |];;
- : float array = [|4.; 6.|]
レコード型の定義に mutable が宣言されているフィールドなら...
#type mutable_point = { mutable x: float; mutable y: flo...
type mutable_point = { mutable x : float; mutable y : fl...
#let translate p dx dy =
p.x <- p.x +. dx; p.y <- p.y +. dy;;
val translate : mutable_point -> float -> float -> unit ...
#let mypoint = { x = 0.0; y = 0.0 };;
val mypoint : mutable_point = {x = 0.; y = 0.}
#translate mypoint 1.0 2.0;;
- : unit = ()
#mypoint;;
- : mutable_point = {x = 1.; y = 2.}
Caml には変数という概念が組み込まれていません。ここで言う...
#let insertion_sort a =
for i = 1 to Array.length a - 1 do
let val_i = a.(i) in
let j = ref i in
while !j > 0 && val_i < a.(!j - 1) do
a.(!j) <- a.(!j - 1);
j := !j - 1
done;
a.(!j) <- val_i
done;;
val insertion_sort : 'a array -> unit = <fun>
次の呼び出しがあるまで現在の状態を保持しなければならない...
#let current_rand = ref 0;;
val current_rand : int ref = {contents = 0}
#let random () =
current_rand := !current_rand * 25713 + 1345;
!current_rand;;
val random : unit -> int = <fun>
再度説明しますが、参照は内部的に実現されているわけではあ...
#type 'a ref = { mutable contents: 'a };;
type 'a ref = { mutable contents : 'a; }
#let (!) r = r.contents;;
val ( ! ) : 'a ref -> 'a = <fun>
#let (:=) r newval = r.contents <- newval;;
val ( := ) : 'a ref -> 'a -> unit = <fun>
型多相な関数を、型多相のままデータ構造に保持しなくてはな...
#type idref = { mutable id: 'a. 'a -> 'a };;
type idref = { mutable id : 'a. 'a -> 'a; }
#let r = {id = fun x -> x};;
val r : idref = {id = <fun>}
#let g s = (s.id 1, s.id true);;
val g : idref -> int * bool = <fun>
#r.id <- (fun x -> print_string "called id\n"; x);;
- : unit = ()
#g r;;
called id
called id
- : int * bool = (1, true)
**1.6 Exceptions [#v16830f1]
Caml では例外状況を伝え、受け取るための例外機構が提供され...
#exception Empty_list;;
exception Empty_list
#let head l =
match l with
[] -> raise Empty_list
| hd :: tl -> hd;;
val head : 'a list -> 'a = <fun>
#head [1;2];;
- : int = 1
#head [];;
Exception: Empty_list.
標準ライブラリの関数は正常に処理を完了できなかったとき例...
#List.assoc 1 [(0, "zero"); (1, "one")];;
- : string = "one"
#List.assoc 2 [(0, "zero"); (1, "one")];;
Exception: Not_found.
例外は try...with でトラップすることが出来ます。
#let name_of_binary_digit digit =
try
List.assoc digit [0, "zero"; 1, "one"]
with Not_found ->
"not a binary digit";;
val name_of_binary_digit : int -> string = <fun>
#name_of_binary_digit 0;;
- : string = "zero"
#name_of_binary_digit (-1);;
- : string = "not a binary digit"
with の部分は、例外の値をパターンマッチングすることが出来...
#let temporarily_set_reference ref newval funct =
let oldval = !ref in
try
ref := newval;
let res = funct () in
ref := oldval;
res
with x ->
ref := oldval;
raise x;;
val temporarily_set_reference : 'a ref -> 'a -> (unit ->...
**1.7 Symbolic processing of expressions [#zc54ea13]
このチュートリアルの最後に、Caml の記号処理の使い方を代表...
#type expression =
Const of float
| Var of string
| Sum of expression * expression (* e1 + e2 *)
| Diff of expression * expression (* e1 - e2 *)
| Prod of expression * expression (* e1 * e2 *)
| Quot of expression * expression (* e1 / e2 *)
;;
type expression =
Const of float
| Var of string
| Sum of expression * expression
| Diff of expression * expression
| Prod of expression * expression
| Quot of expression * expression
変数名に値を割り当てた環境から、計算式を評価する関数を定...
#exception Unbound_variable of string;;
exception Unbound_variable of string
#let rec eval env exp =
match exp with
Const c -> c
| Var v ->
(try List.assoc v env with Not_found -> raise(Unb...
| Sum(f, g) -> eval env f +. eval env g
| Diff(f, g) -> eval env f -. eval env g
| Prod(f, g) -> eval env f *. eval env g
| Quot(f, g) -> eval env f /. eval env g;;
val eval : (string * float) list -> expression -> float ...
#eval [("x", 1.0); ("y", 3.14)] (Prod(Sum(Var "x", Const...
- : float = 9.42
本当の記号処理として、与えられた式の与えられた変数 dv で...
#let rec deriv exp dv =
match exp with
Const c -> Const 0.0
| Var v -> if v = dv then Const 1.0 else Const 0.0
| Sum(f, g) -> Sum(deriv f dv, deriv g dv)
| Diff(f, g) -> Diff(deriv f dv, deriv g dv)
| Prod(f, g) -> Sum(Prod(f, deriv g dv), Prod(deriv f...
| Quot(f, g) -> Quot(Diff(Prod(deriv f dv, g), Prod(f...
Prod(g, g))
;;
val deriv : expression -> string -> expression = <fun>
#deriv (Quot(Const 1.0, Var "x")) "x";;
- : expression =
Quot (Diff (Prod (Const 0., Var "x"), Prod (Const 1., Co...
Prod (Var "x", Var "x"))
**1.8 Pretty-printing and parsing [#na8dcc74]
上の例で示された例では、少し式が大きくなるだけで、式の内...
プリンタの関数が不要なカッコを表記しないで済むように、演...
#let print_expr exp =
(* Local function definitions *)
let open_paren prec op_prec =
if prec > op_prec then print_string "(" in
let close_paren prec op_prec =
if prec > op_prec then print_string ")" in
let rec print prec exp = (* prec is the current p...
match exp with
Const c -> print_float c
| Var v -> print_string v
| Sum(f, g) ->
open_paren prec 0;
print 0 f; print_string " + "; print 0 g;
close_paren prec 0
| Diff(f, g) ->
open_paren prec 0;
print 0 f; print_string " - "; print 1 g;
close_paren prec 0
| Prod(f, g) ->
open_paren prec 2;
print 2 f; print_string " * "; print 2 g;
close_paren prec 2
| Quot(f, g) ->
open_paren prec 2;
print 2 f; print_string " / "; print 3 g;
close_paren prec 2
in print 0 exp;;
val print_expr : expression -> unit = <fun>
#let e = Sum(Prod(Const 2.0, Var "x"), Const 1.0);;
val e : expression = Sum (Prod (Const 2., Var "x"), Cons...
#print_expr e; print_newline();;
2. * x + 1.
- : unit = ()
#print_expr (deriv e "x"); print_newline();;
2. * 1. + 0. * x + 0.
- : unit = ()
(具体文法から抽象文法に変換する) パージングは大抵プリント...
##load "camlp4o.cma";;
Camlp4 Parsing version 3.05 (2002-07-22)
#open Genlex;;
let lexer = make_lexer ["("; ")"; "+"; "-"; "*"; "/"];;
val lexer : char Stream.t -> Genlex.token Stream.t = <fun>
(与えられた文字列をトークンのストリームに変換する) 字句解...
#let token_stream = lexer(Stream.of_string "1.0 +x");;
val token_stream : Genlex.token Stream.t = <abstr>
#Stream.next token_stream;;
- : Genlex.token = Float 1.
#Stream.next token_stream;;
- : Genlex.token = Kwd "+"
#Stream.next token_stream;;
- : Genlex.token = Ident "x"
パージング自体はトークンのストリームをパターンマッチング...
対話式システムのトップレベルでストリームパーザを使用する...
##load"camlp4o.cma";;
Camlp4 Parsing version 3.05 (2002-07-22)
それからパーザを定義します。
#let rec parse_expr = parser
[< e1 = parse_mult; e = parse_more_adds e1 >] -> e
and parse_more_adds e1 = parser
[< 'Kwd "+"; e2 = parse_mult; e = parse_more_adds (...
| [< 'Kwd "-"; e2 = parse_mult; e = parse_more_adds (...
| [< >] -> e1
and parse_mult = parser
[< e1 = parse_simple; e = parse_more_mults e1 >] -> e
and parse_more_mults e1 = parser
[< 'Kwd "*"; e2 = parse_simple; e = parse_more_mult...
| [< 'Kwd "/"; e2 = parse_simple; e = parse_more_mult...
| [< >] -> e1
and parse_simple = parser
[< 'Ident s >] -> Var s
| [< 'Int i >] -> Const(float i)
| [< 'Float f >] -> Const f
| [< 'Kwd "("; e = parse_expr; 'Kwd ")" >] -> e;;
val parse_expr : Genlex.token Stream.t -> expression = <...
val parse_more_adds : expression -> Genlex.token Stream....
<fun>
val parse_mult : Genlex.token Stream.t -> expression = <...
val parse_more_mults : expression -> Genlex.token Stream...
<fun>
val parse_simple : Genlex.token Stream.t -> expression =...
#let parse_expression = parser [< e = parse_expr; _ = St...
val parse_expression : Genlex.token Stream.t -> expressi...
字句解析器と構文解析器を作成し、文字列から計算式を読む関...
#let read_expression s = parse_expression(lexer(Stream.o...
val read_expression : string -> expression = <fun>
#read_expression "2*(x+y)";;
- : expression = Prod (Const 2., Sum (Var "x", Var "y"))
ちょっとしたクイズです。なぜ以下の 2 つの例は結果が異なる...
#read_expression "x - 1";;
- : expression = Diff (Var "x", Const 1.)
#read_expression "x-1";;
Exception: Stream.Error "".
答えです。Genlex の字句解析器は負の整数を 1 つの整数とし...
**1.9 Standalone Caml programs [#lceb9c2e]
今までは対話式システムですべての例を実行してきました。Cam...
(* File fib.ml *)
let rec fib n =
if n < 2 then 1 else fib(n-1) + fib(n-2);;
let main () =
let arg = int_of_string Sys.argv.(1) in
print_int(fib arg);
print_newline();
exit 0;;
main ();;
Sys.argv はコマンドライン引数の文字列の配列です。Sys.argv...
$ ocamlc -o fib fib.ml
$ ./fib 10
89
$ ./fib 20
10946
ページ名: