1から5までの数を単語にするとone,two,three,four,fiveとなり、全部で 3+3+5+4+4=19文字になる。
1から1000までの全ての数を単語にすると何文字になるか求めよ。
(注)スペースやハイフンは数に含めない。例えば342(three hundred and forty-two)は23文字、115(one hundred and fifteen)は20文字である。andの使 い方はイギリス方式である。
題意のとおりに、1から1000までの数を単語であらわしたものを求め、その文字 数の和を求めることにする。数を単語であらわす関数inwordsを以下のように定 義する。20以下の場合は単語のリストから単語を取り出す。20以上の場合は10 の位と1の位をそれぞれリストから求める。100以上になるとさらに100の位を別 に求めて連結する。問題自体は決して難しくないが、ネイティブでない場合、 数の英語表記を間違えないように注意する必要がある。とくにつづりを間違え ただけでも答えを間違ってしまう。100の位とその下の間にandをつけるがちょ うど100の時にはつけないなども注意が必要だ。
euler017 = sum $ map (length . inwords) [1..1000]
where words1 = [ "",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten",
"eleven",
"twelve",
"thirteen",
"fourteen",
"fifteen",
"sixteen",
"seventeen",
"eighteen",
"nineteen"]
words10 = [ "",
"",
"twenty",
"thirty",
"forty",
"fifty",
"sixty",
"seventy",
"eighty",
"ninety" ]
inwords n
| n < 20 = words1 !! n
| n >= 20 && n < 100 = let (d, m) = divMod n 10
in words10 !! d ++ inwords m
| n >= 100 && n < 1000 = let (d, m) = divMod n 100
lower = if m /= 0
then "and" ++ inwords m
else ""
in inwords d ++ "hundred" ++ lower
| n == 1000 = "onethousand"
