let rec quick = function [] -> [] | [x] -> [x] | x :: xs -> (* x is the pivot *) let rec partition left right = function [] -> (quick left) @ (x :: quick right) | y :: ys -> if x < y then partition left (y :: right) ys else partition (y :: left) right ys in partition [] [] xs;;
let rec quicker l sorted = match l with [] -> sorted | [x] -> x :: sorted | x :: xs -> (* x is the pivot *) let rec partition left right = function [] -> quicker left (x :: quicker right sorted) | y :: ys -> if x < y then partition left (y :: right) ys else partition (y :: left) right ys in partition [] [] xs;;
# quicker [2; 3; 9; 1; 5; 4] [];; - : int list = [1; 2; 3; 4; 5; 9]
# (fun x -> 'h'::'o'::'g'::'e'::x) "foobar";; This expression("foobar") has type string but is here used with type char list
(* fromからtoまでの数列を生成 *) let rec range from_value to_value = if from_value > to_value then [] else from_value::(range (from_value + 1) to_value);; (* 整数版sqrt *) let sqrt_int x = int_of_float (sqrt (float_of_int x));; let f r x xs= let y = sqrt_int(r - x*x) in if x > y && (x*x + y*y = r) then (x,y)::xs else xs;; let squares r = List.fold_right (f r) (range 0 (sqrt_int r)) [];;
let rec rev l1 l2 = match l1 with [] -> l2 | x::rest -> rev rest (x::l2);; let map2 f = let rec map'f res = function [] -> rev res [] | x::rest -> map' f((f x)::res) rest in map' f [];;
継続渡しスタイル (Continuation Passing Style)と呼ぶこともあります。
let map2 f xs = let rec map' f ys k = match ys with [] -> k [] | y'::ys' -> map' f ys' (fun zs -> k (f y'::zs)) in map' f xs (fun x->x);;ここで
| y'::ys' -> map' f ys' (fun zs -> f y' :: k zs)とやってしまった。結果リストが逆順になる…thx to みずの
map' f (x:xs) k = map' f xs (?ys->k (f x:ys)) map' f [] k = k []
どうやって計る?体感的には同じ位に思えた。
とりあえず,ベンチマークしてみました.(樋口)
教科書中にあった指定した長さの乱数のリストを得る関数
let nextrand seed = let a = 16807.0 and m = 2147483647.0 in let t = a *. seed in t -. m *. floor(t /. m) let rec randlist n seed tail = if n = 0 then (seed,tail) else randlist (n-1) (nextrand seed) (seed::tail)
これを使い,長さ10000000のリストを用意し, すべての要素を+1するような実験を行いました.
let _ = map2 (fun x -> x +. 1.0) (snd (randlist 10000000 1.0 []));;
ex8a, ex8bは共にocamlc.opt -o ex8a ex8a.ml といったように特にオプションなしでコンパイルしました.
Command being timed: "./ex8a" User time (seconds): 18.46 System time (seconds): 0.68 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:19.31 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 0 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 163 Minor (reclaiming a frame) page faults: 114564 Voluntary context switches: 0 Involuntary context switches: 0 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0
Command being timed: "./ex8b" User time (seconds): 19.82 System time (seconds): 3.68 Percent of CPU this job got: 11% Elapsed (wall clock) time (h:mm:ss or m:ss): 3:31.57 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 0 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 30614 Minor (reclaiming a frame) page faults: 628565 Voluntary context switches: 0 Involuntary context switches: 0 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0
User timeを見ると似たようなものですけど, System timeやpage faultをみてみると ex8bは,激しくメモリを消費中?
nat上で int_of_nat, mul, monus を定義せよ
参考 nat の定義 type nat = Zero | OneMoreThan of nat ;;
let rec int_of_nat = function Zero -> 0 | OneMoreThan n -> 1 + int_of_nat n;;
let rec add m n = match m with Zero -> n | OneMoreThan m' -> OneMoreThan (add m' n);; が定義されているとして let rec mul m n = match m with Zero -> Zero | OneMoreThan Zero -> n | OneMoreThan m' -> add n (mul m' n);; let rec monus m n = match m with Zero -> Zero | OneMoreThan m' -> match n with Zero -> OneMoreThan m' | OneMoreThan n' -> monus m' n';;
let rec minus m n = match (m, n) with (m, Zero) -> Some m | (Zero, _) -> None | (OneMoreThan k, OneMoreThan l) -> minus k l;;
(* inord *) let rec inord t l = match t with Lf -> l | Br(x,left,right) -> (inord left (x :: inord right l));;
(* postord *) let rec postord t l = match t with Lf -> l | Br(x,left,right) -> (postord left (postord right (x::l)));;
一応、ここで使った二分木の定義。
type 'a tree = Lf | Br of 'a * 'a tree * 'a tree;;
ごめんなさい、結構難しい...ToT すぐにできないので、宿題とさせてください。