Haskell再び、簡単なところから
Haskellは一旦あっさり諦めようと思ってたけど、結局、オライリーから出ている「Real World Haskll」という本を買ってしまって、また読み始めている。漆塗り勉強法。薄く何度も繰り返し塗る。
で、少し読み進めたらまた何か簡単なものなら書けそうな気がしてきて、以下の問題をHaskellで解いてみた。
「2乗した結果に1から9までの数字が1度ずつ現れる整数をすべて挙げよ」。
以前にRubyで書いたのは以下。
def has9digits? (num) exit if num.to_s.size >= 10 digits = num.to_s.split(//).sort.join digits == "123456789" end 1.upto(10000000) do |i| print i," * ",i," = ",i**2,"\n" if has9digits?(i**2) end
結果は、
% ruby 9digi.rb 11826 * 11826 = 139854276 12363 * 12363 = 152843769 12543 * 12543 = 157326849 14676 * 14676 = 215384976 15681 * 15681 = 245893761 15963 * 15963 = 254817369 18072 * 18072 = 326597184 19023 * 19023 = 361874529 19377 * 19377 = 375468129 19569 * 19569 = 382945761 19629 * 19629 = 385297641 20316 * 20316 = 412739856 22887 * 22887 = 523814769 23019 * 23019 = 529874361 23178 * 23178 = 537219684 23439 * 23439 = 549386721 24237 * 24237 = 587432169 24276 * 24276 = 589324176 24441 * 24441 = 597362481 24807 * 24807 = 615387249 25059 * 25059 = 627953481 25572 * 25572 = 653927184 25941 * 25941 = 672935481 26409 * 26409 = 697435281 26733 * 26733 = 714653289 27129 * 27129 = 735982641 27273 * 27273 = 743816529 29034 * 29034 = 842973156 29106 * 29106 = 847159236 30384 * 30384 = 923187456
という感じ。
同じ発想で、Haskellでも書いてみた。
import List main = do putStrLn $ format $ filter isNinedigit [1..100000] isNinedigit :: Int -> Bool isNinedigit n = if (x == "123456789") then True else False where x = sort $ show (n * n) format :: [Int] -> String format (n:ns) = a ++ " * " ++ a ++ " = " ++ b ++ "\n" ++ (format ns) where a = (show n) b = (show (n * n)) format [] = ""
これでほぼ動いている。なぜか上限を突破して、おかしな数字が出つづける。
29034 * 29034 = 842973156 29106 * 29106 = 847159236 30384 * 30384 = 923187456 67759 * 67759 = 296314785 69041 * 69041 = 471692385 70121 * 70121 = 621987345 71467 * 71467 = 812564793
30384 * 30384 = 923187456までは確かに成立してるけど、67759 * 67759 = 296314785はおかしい。うーん。単純にIntが32ビットで桁溢れを起こしてるだけか。67759 * 67759 = 4591282081で45億だから溢れてるっぽい。
おお、「67759**2 - 0x100000000 => 296314785」だった。なるほど、確かに一巡してそうなってるわ。では、こういう場合、停止条件を書きたいんだけど、Haskellだとどうするんだろうか。あらかじめ2乗してそれが32ビット以下であることを前提にする関数を作るとか? そのとき、各数字の2乗の計算結果ってちゃんと再利用されるのかしら。
あ、パターンマッチで再帰してるところは何か書き間違えてる気がする。x:xs、x、[]の3種類が必要かな? あとで確認する。
数字を扱ったパズルとかだとRubyのようなFixnumとBignumを勝手に切り替えてくれる仕様はありがたいなぁ。