OCamlの練習

4けたの数について、それぞれの位の数字を大きいじゅんにならべた数から小さいじゅんにならべた数をひくという計算を行います。

1974 について、この計算を 100 回行った答えを書きなさい。

http://d.hatena.ne.jp/cooldaemon/20120603/1338705617

上の問題をOCamlで書いてみました(OCaml勉強中です)。

let digits n =
    assert (n >= 0);
    let rec loop n =
        if n = 0 then []
        else loop (n/10) @ [n mod 10]
    in
    if n = 0 then [0]
    else loop n

let toint xs =
    let rec ti xs acc = match xs with
      [] -> acc
    | x::xs -> ti xs (10 * acc + x)
    in
    ti xs 0

let calc n =
    let xs = List.sort compare (digits n) in
    toint (List.rev xs) - toint xs

let main n =
    let rec loop n m =
        if m = 0 then n
        else loop (calc n) (m - 1)
    in
    loop n 100

実行結果です。

# #use "a.ml";;
val digits : int -> int list = <fun>
val toint : int list -> int = <fun>
val calc : int -> int = <fun>
val main : int -> int = <fun>
# main 1974;;
- : int = 6174

以下、メモです。

  • letの書き方が分からなくてシンタックスエラーが大量に出た。let と let ... in の違いがよく分かっていなかったので、それに気をつけるとシンタックスエラーは大分減った。
  • リストを連結するには @ を使う。
# [1] @ [2; 3];;
- : int list = [1; 2; 3]
# [1; 2] @ [3];;
- : int list = [1; 2; 3]
# [] @ [];;
- : 'a list = []
# [] @ [2];;
- : int list = [2]
# (@);;
- : 'a list -> 'a list -> 'a list = <fun>
# (@) [1];;
- : int list -> int list = <fun>
# (@) [1] [2];;
- : int list = [1; 2]
# ((@) [1]) [3];;
- : int list = [1; 3]