http://projecteuler.net/index.php?section=problems&id=36
10進の回文数を再帰的に出して、2進で回文数になるかを調べます。
パイプライン処理というのを使ってみました。例えば、数字のリストがあってリストを逆にして10進数にする処理というのは通常、
let to_number a = List.fold (fun x y -> x * 10 + y) 0 a printfn "%d" (to_number (List.rev [1; 2; 3])) // 321
こうですが、
printfn "%d" ([1; 2; 3] |> List.rev |> to_number) // 321
とも書けます。データの流れが左から右になっています。
以前、Haskellに対する批判で思考の順序と書き方が逆、というのをどこかで見ました。そのような批判に対する答えがこれなのでしょうか。
ただ、これは単に慣れの問題のような気がします。Project Eulerでよく「〜の和を求めよ」という問題がありますが(この問題もそうでしたね)、Haskellだと、
sum (...)
と書きます。F#のパイプライン処理だと、
... |> Seq.sum
と「〜の和」というのと順序が一致しますね。
しかし、英語では「Find the sum of ...」となります。Haskellの順序ですね。思考の順序は人それぞれで、必ずしもパイプライン処理が自然というわけではないと思います。
let N = 6 let rec pow n e = if e = 0 then 1 else n * (pow n (e - 1)) let rec palindrome n zero_leading = if n = 1 then if zero_leading then seq { 0..9 } else seq { 1..9 } else if n = 2 then if zero_leading then seq { 0..11..99 } else seq { 11..11..99 } else let d = (pow 10 (n - 1)) + 1 seq { for p in palindrome (n - 2) true do for q in d..d..d*9 -> p * 10 + q } let rec binary n = if n = 0 then [] else (binary (n >>> 1)) @ [n &&& 1] let to_number a = List.fold (fun x y -> x * 2 + y) 0 a let is_palindromic_bin n = n = (n |> binary |> List.rev |> to_number) let s = seq { for n in 1..N do for m in palindrome n false -> m } printfn "%d" (Seq.sum (Seq.filter is_palindromic_bin s))