I stumbled upon the blog entry A Decimal to Roman Numeral converter in just a few lines where a Clojure function with `loop/recur`

was presented. The solution was very concise yet it used `loop/recur`

which I decided to replace with the functional trio – `map`

, `reduce`

and `filter`

.

I knew I could make it, but after a nothing-but-scratching-my-head hour or two I began googling for a hint. After a sec Google pointed me to using reduce instead of loop recur and life turned bright. Or so thought I.

The first version was as follows. Lots of parentheses, two `first`

‘s at the beginning and although I made out well – no `loop/recur`

combo, I was far from being proud of my achievement. I called it a partial success, but learnt a lot – `drop-while`

and `iterate`

were a bonus.

100 "C" 90 "XC" 50 "L" 40 "XL"

10 "X" 9 "IX" 5 "V" 4 "IV" 1 "I"))

(defn arabic->roman [n]

(first

(first

(drop-while (comp (complement nil?) second)

(iterate

(fn [[reminder roman]]

(if (zero? reminder)

[roman nil]

(let [curr-num (first (filter (partial >= reminder) (keys mapping)))]

[(- reminder curr-num) (str roman (get mapping curr-num))])))

[n ""])))))

And the other three days passed as I was tinkering the solution above to find a better version with `map/reduce/filter`

trio. I believe that to truly appreciate expressiveness of functional programming one has to solve problems with it. Here’s the other version with `reduce`

and `filter`

. Not bad, isn’t it?

(:roman

(reduce

(fn [state rv]

(let [{:keys [roman number]} state

[arabic-num roman-number] rv

quotient (quot number arabic-num)]

(if (>= quotient 0)

{:roman (str roman (apply str (repeat quotient roman-number)))

:number (- number (* quotient arabic-num))}

state)))

{:roman "" :number n}

(-> #(>= n (first %))

(filter mapping)))))

But it’s still ugly, too verbose, reads badly and so does it look. I tried to spice it up a bit with destructuring to make the code a little smaller, but still it’s too cumbersome. I wish I had come up with a better version, but it will take time for sure. Hopefully, someone will share a better version of the problem with the functional trio – `map`

, `reduce`

and `filter`

that will look better, slimmer and effective. If it could attract a Clojure novice’s eye, it’d be so much better. Anyone? Thanks!

p.s. Have a read of the comments in the blog entry A Decimal to Roman Numeral converter in just a few lines where you can find a solution with `clojure.pprint/cl-format`

. What’s a one-liner! The function is a part of the Clojure library and it’s obvious now (after I’ve seen it) that the conversion should really be part of the `clojure.pprint`

.

I’d love to see syntax coloring here :E

Any advices? I can’t find a viable coloring syntax highlighter for the site.

This is one of the problems on 4clojure. Here is my solution, for the sake of comparison:

(apply str

(let [roman (str roman)

i "IXCM"

v "VLD"

x "XCM"

ms {\1 [i] \2 [i i] \3 [i i i]

\4 [i v] \5 [v] \6 [v i]

\7 [v i i] \8 [v i i i] \9[i x]}

powers (reverse (range (count roman)))]

(mapcat

(fn [power digit]

(map

#((vec %) power)

(ms digit)))

powers

roman))))

Thanks for the solution. A very bright one and I could learn a lot! It once again proves that without algorithmic background every problem can become way too hard to solve in any language (which is just another way to write (executable) sentences). I believe, thought, that with more and more such small(ish) functional applications I’ll spot patterns and apply right solutions more quicker. Thanks!

One point: I’d change

to

around

.