http://projecteuler.net/index.php?section=problems&id=4
全ての組合せに対し、回文数であるかどうか判定し、回文数の中で最大のものを求めます。
回文数の判定は、各桁の数字ごとのリストにし、それを逆にし、数に戻して元の数と同じか調べます。
まず、数字のリストにするのは再帰で簡単に書けます。
let rec digits n = if n = 0 then [] else (digits (n / 10)) @ [n % 10]
@はリストの結合です。
逆順にする関数はList.revです。
再び数に戻すのは素直にfoldで書きます。
let to_number s = List.fold (fun x y -> x * 10 + y) 0 s
F#にも内包表記があります。
let a = [ for i in 1..5 -> i * i ] printfn "%A" a
[1; 4; 9; 16; 25]
2次元の例は見当たらなかったのですが、適当に試行錯誤したらできました。
let a = [ for x in 1..3 do for y in x..3 -> (x, y) ] printfn "%A" a
[(1, 1); (1, 2); (1, 3); (2, 2); (2, 3); (3, 3)]
これでこの問題は解けます。
let rec digits n = if n = 0 then [] else (digits (n / 10)) @ [n % 10] let to_number s = List.fold (fun x y -> x * 10 + y) 0 s let is_palindromic n = n = to_number (List.rev (digits n)) printfn "%d" (List.max (List.filter is_palindromic [ for n in 100..999 do for m in n..999 -> n * m ]))
タスクマネージャ見たところ、これって勝手に並列化しているみたいですね。
でも、数を大きくするとメモリをやたらと食います、遅延評価しないので。Sequence同じです。
printfn "%d" (Seq.max (Seq.filter is_palindromic (seq [ for n in 100..999 do for m in n..999 -> n * m ])))
内包表記は捨ててこう書くと遅延評価するようですね(数の範囲を変えている)。
let s = seq { for n in 300..2999 do for m in n..2999 do yield n * m } printfn "%d" (Seq.max (Seq.filter is_palindromic s))
Haskellの倍近く実行時間がかかります。