久しぶりにocaml
ocamllexとかocamlyaccとかを使う前に、ocamlの文法とかを忘れてしまっているような気がする。
何か問題を解いて思い出そう。
与えられた正の整数のローマ数字表現(文字列)を求める関数roman(I = 1,V = 5,X = 10,L = 50,C = 100,D = 500,M = 1000)。
schemeで書くときと同じように考えると、回答結果に簡単に変換できるリストが作成できたら終了という感じがする。
とりあえず、[("D" . 1);("I" . 3)]みたいなリストを作成する関数を作ってみよう。
let roman dic n = let rec finder items x found= match items with | (sym, value) :: rest -> if value > x then finder rest x found else found x sym value and iter dic n result = if n = 0 then List.rev result else finder dic n (fun x sym v -> iter (List.tl dic) (n mod v) ((sym , (n / v)) :: result)) in iter dic n [];; let dic = [ ("M" , 1000); ("D" , 500); ("C" , 100); ("L", 50); ("X" , 10); ("V", 5); ("I", 1) ];; roman dic 503 (* # roman dic 503;; *) (* - : (string * int) list = [("D", 1); ("I", 3)] *)
返すのはリストじゃなくて、文字列だった。
あと、パターンマッチが網羅されてないみたいなwarningがでた。
たしかStringをfoldと^で作成するのは無駄な文字列が作成されてしまいよくなかった様な気がする。
Bufferとか使うんだったかな?
Bufferを作ってそこにpushしていく感じで作れるのかな?
リストから一気に合体させた方がいいような気もする。
String.concatとかあったっけ?
stringを文字と数字から作成する方法はどうやるんだろう?>String.makeっぽい。
今回は、Bufferを使わないでつくろう。
あと、見つからなかったときに例外を返すようにして、Warningを消そう。
let roman2 dic n = let rec finder items x found= match items with | (sym, value) :: rest -> if value > x then finder rest x found else found x sym value | _ -> raise Not_found and iter dic n result = if n = 0 then List.rev result else finder dic n (fun x sym v -> iter (List.tl dic) (n mod v) ((String.make (n / v) sym) :: result)) in String.concat "" (iter dic n []) let dic = [ ('M' , 1000); ('D' , 500); ('C' , 100); ('L', 50); ('X' , 10); ('V', 5); ('I', 1) ];; let roman_of_int = roman2 dic;; roman_of_int 101;; roman_of_int 1234;; roman_of_int 1984;; roman_of_int (-1);; (* # let roman_of_int = roman2 dic;; *) (* val roman_of_int : int -> string = <fun> *) (* # roman_of_int 101;; *) (* - : string = "CI" *) (* # roman_of_int 1234;; *) (* - : string = "MCCXXXIIII" *) (* # roman_of_int 1984;; *) (* - : string = "MDCCCCLXXXIIII" *) (* # roman_of_int (-1);; *) (* Exception: Not_found. *)