ローマ数字を求める
1..3999の数字をローマ数字に変換する。
あとでググってみたら、ワンライナーとかすごそうなのが色々あったけど、自分としては今の実装で充分読みやすいと思った。Maybeを使って範囲外はNothingにしたりしてみたけど、このあたり空気は読めてない。
パターンマッチングは粗々こんな感じだろうけど、むしろモナドがでてくるここからがヤマなのだろう。
8/14追記:最初roman n の n mod 10|100|1000が0になるケースのパターンを網羅してなかった。実はそのことは知ってたんだけど、問題ないと思ってたら、roman 1900とかでエラーになったのでrecurなる関数を導入してきちんと漏れのないようにした。
パターンに漏れは禁物なんだな。
module Roman where roman' n one five ten | n == 0 = [] | n == 4 = [one, five] | n == 5 = [five] | n == 9 = [one, ten] | n > 5 = five : ( roman' (n-5) one five ten ) | otherwise = (roman' (n-1) one five ten) ++ [one] roman n | 1 <= n && n < 10 = roman' n 'I' 'V' 'X' | 10 <= n && n < 100 = roman' (div n 10) 'X' 'L' 'C' ++ recur (mod n 10) | 100 <= n && n < 1000 = roman' (div n 100) 'C' 'D' 'M' ++ recur (mod n 100) | 1000 <= n && n < 4000 = roman' (div n 1000) 'M' '-' '-' ++ recur (mod n 1000) where recur n | n == 0 = [] | otherwise = roman n chkroman n | n < 1 = Nothing | n < 4000 = Just $ roman n | otherwise = Nothing