Here's a little toy to practice my basic Clojure skills. I didn't see any similar topic in the archives, so here we go...
This code performs conversions between Roman and Arabic numerals. Roman numerals are represented as strings and Arabic numerals are just integers. Arabic numerals in the range of 1 and 3999 inclusive are allowed. Conventionally, 3999 is the upper limit since the Roman numeral for 5000 (a V with a bar over it) cannot be represented in ASCII (although it exists in Unicode). The function roman-to-arabic-aux correctly converts any valid Roman numeral. This can be exhaustively tested by comparing the Roman numeral output of Common Lisp's FORMAT function for example (e.g., (format nil "~...@r" n)). The trick, however, is weeding out bogus strings representing invalid Roman numerals such as IVI, IXV, etc... For this purpose the function "roman?" uses a regular expression I cribbed from Perl's CPAN module Roman.pm (http://search.cpan.org/ ~chorny/Roman-1.23/lib/Roman.pm). arabic-to-roman performs the obvious conversion in the other direction. Incidentally, the "cond" form in roman-to-arabic-aux seems to me harder to read in Clojure than it would be in CL with its additional set of grouping parentheses. When you can't fit both the predicate and the consequent expression on the same line it gets confusing. I'd appreciate any feedback regarding my Clojure style. Any more natural ways to do things? Aloha, David Sletten (def roman-values-map {\I 1 \V 5 \X 10 \L 50 \C 100 \D 500 \M 1000}) (defn value [roman] (get roman-values-map (Character/toUpperCase roman))) (defn roman? [roman-string] (and (not (empty? roman-string)) (re-matches #"(?:M{0,3})(?:D?C{0,3}|C[DM])(?:L?X{0,3}|X[LC])(?:V?I{0,3}|I [VX])$" roman-string))) (defn roman-to-arabic-aux [roman-string] (cond (empty? roman-string) 0 (empty? (rest roman-string)) (value (first roman-string)) (< (value (first roman-string)) (value (second roman-string))) (- (roman-to-arabic-aux (rest roman-string)) (value (first roman-string))) :else (+ (value (first roman-string)) (roman-to-arabic-aux (rest roman-string))))) (defn roman-to-arabic [roman-string] (if (roman? roman-string) (roman-to-arabic-aux roman-string) (format "'%s' is not a valid Roman numeral." roman-string))) (def arabic-values '((1000 "M") (900 "CM") (500 "D") (400 "CD") (100 "C") (90 "XC") (50 "L") (40 "XL") (10 "X") (9 "IX") (5 "V") (4 "IV") (1 "I"))) (defn arabic-to-roman ([n] (if (<= 1 n 3999) (apply str (arabic-to-roman n arabic-values)) (format "%d cannot be converted." n))) ([n num-list] (cond (empty? num-list) '() (zero? n) '() :else (let [[[arabic roman] & tail] num-list] (if (>= n arabic) (cons roman (arabic-to-roman (- n arabic) num-list)) (arabic-to-roman n tail)))) )) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---