For Project Euler Problem 17, I fell back to a more C-style pattern (almost like a big case statement). This is admittedly not the most beautiful solution, but I am comfortable with that as the problem itself doesn’t hide any particular mathematical elegance.
(defn tens [n s sub]
(if (zero? (mod n 10))
s
(apply str (concat s "-"(verbally (- n sub))))))
(defn hundreds [n s sub]
(if (zero? (mod n 100))
(apply str (concat s "-hundred"))
(apply str (concat s "-hundred and "(verbally (- n sub))))))
(defn verbally [n]
(cond
(= n 1) "one"
(= n 2) "two"
(= n 3) "three"
(= n 4) "four"
(= n 5) "five"
(= n 6) "six"
(= n 7) "seven"
(= n 8) "eight"
(= n 9) "nine"
(= n 10) "ten"
(= n 11) "eleven"
(= n 12) "twelve"
(= n 13) "thirteen"
(= n 14) "fourteen"
(= n 15) "fifteen"
(= n 16) "sixteen"
(= n 17) "seventeen"
(= n 18) "eighteen"
(= n 19) "nineteen"
(< n 30) (tens n "twenty" 20)
(< n 40) (tens n "thirty" 30)
(< n 50) (tens n "forty" 40)
(< n 60) (tens n "fifty" 50)
(< n 70) (tens n "sixty" 60)
(< n 80) (tens n "seventy" 70)
(< n 90) (tens n "eighty" 80)
(< n 100) (tens n "ninety" 90)
(< n 200) (hundreds n "one" 100)
(< n 300) (hundreds n "two" 200)
(< n 400) (hundreds n "three" 300)
(< n 500) (hundreds n "four" 400)
(< n 600) (hundreds n "five" 500)
(< n 700) (hundreds n "six" 600)
(< n 800) (hundreds n "seven" 700)
(< n 900) (hundreds n "eight" 800)
(< n 1000) (hundreds n "nine" 900)
(= n 1000) "one thousand"
true "BIG NUMBER"
))
(defn lc-alpha? [char]
(some #(= char %) "abcdefghijklmnopqrstuvwxyz"))
(defn euler-17 []
(count (filter lc-alpha? (apply concat (map verbally (range 1 1001))))))
Obviously, the verbally
function is the problem. Packaging up that cond statement into something more elegant (such as an array) would go a long way towards making this shorter, as some people at clojure-euler did for this problem. I leave further exploration to them.
Finally, it’s interesting to also think about the question “What if other languages besides English have strange ways of counting that require some strange conditional patterns? “ For example, the French say “quatre-vingt-dix” (four twenties and ten) for the number 90, the Germans count in an irregular order (e.g. einhunderteinundzwanzig = “one-hundred, one-and-twenty”), and the Japanese don’t even break things into groups of thousands, millions, billions the way europeans do (Japanese count by groups of 10,000 not 1,000. They would say the number 1,000,000 as “one-hundred ten-thousands”).
How would one extend their code to work multi-lingually, or would it be wiser just to hand code a new function for each language?