Avatar of LaFeeVert

LaFeeVert's solution

to Roman Numerals in the Common Lisp Track

Published at Feb 29 2020 · 0 comments
Test suite

Write a function to convert from normal numbers to Roman Numerals.

The Romans were a clever bunch. They conquered most of Europe and ruled it for hundreds of years. They invented concrete and straight roads and even bikinis. One thing they never discovered though was the number zero. This made writing and dating extensive histories of their exploits slightly more challenging, but the system of numbers they came up with is still in use today. For example the BBC uses Roman numerals to date their programmes.

The Romans wrote numbers using letters - I, V, X, L, C, D, M. (notice these letters have lots of straight lines and are hence easy to hack into stone tablets).

 1  => I
10  => X
 7  => VII

There is no need to be able to convert numbers larger than about 3000. (The Romans themselves didn't tend to go any higher)

Wikipedia says: Modern Roman numerals ... are written by expressing each digit separately starting with the left most digit and skipping any digit with a value of zero.

To see this in practice, consider the example of 1990.

In Roman numerals 1990 is MCMXC:

1000=M 900=CM 90=XC

2008 is written as MMVIII:

2000=MM 8=VIII

See also: http://www.novaroma.org/via_romana/numbers.html


Check out Installing Common Lisp for instructions to get started or take a look at the guides available in the track's side bar.


While Common Lisp doesn't care about indentation and layout of code, nor whether you use spaces or tabs, this is an important consideration for submissions to exercism.io. Excercism.io's code widget cannot handle mixing of tab and space characters well so using only spaces is recommended to make the code more readable to the human reviewers. Please review your editors settings on how to accomplish this. Below are instructions for popular editors for Common Lisp.


Use the following commands to ensure VIM uses only spaces for indentation:

:set tabstop=2
:set shiftwidth=2
:set expandtab

(or as a oneliner :set tabstop=2 shiftwidth=2 expandtab). This can be added to your ~/.vimrc file to use it all the time.


Emacs is very well suited for editing Common Lisp and has many powerful add-on packages available. The only thing that one needs to do with a stock emacs to make it work well with exercism.io is to evaluate the following code:

(setq-default indent-tabs-mode nil)

This can be placed in your ~/.emacs (or ~/.emacs.d/init.el) in order to have it set whenever Emacs is launched.

One suggested add-on for Emacs and Common Lisp is SLIME which offers tight integration with the REPL; making iterative coding and testing very easy.


The Roman Numeral Kata http://codingdojo.org/cgi-bin/index.pl?KataRomanNumerals

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.


(ql:quickload "lisp-unit")
#-xlisp-test (load "roman-numerals")

(defpackage #:roman-test
  (:use #:cl #:lisp-unit))

(in-package #:roman-test)

(define-test test-1
  (assert-equal "I" (roman:romanize 1)))

(define-test test-2
  (assert-equal "II" (roman:romanize 2)))

(define-test test-3
  (assert-equal "III" (roman:romanize 3)))

(define-test test-4
  (assert-equal "IV" (roman:romanize 4)))

(define-test test-5
  (assert-equal "V" (roman:romanize 5)))

(define-test test-6
  (assert-equal "VI" (roman:romanize 6)))

(define-test test-9
  (assert-equal "IX" (roman:romanize 9)))

(define-test test-27
  (assert-equal "XXVII" (roman:romanize 27)))

(define-test test-48
  (assert-equal "XLVIII" (roman:romanize 48)))

(define-test test-59
  (assert-equal "LIX" (roman:romanize 59)))

(define-test test-93
  (assert-equal "XCIII" (roman:romanize 93)))

(define-test test-141
  (assert-equal "CXLI" (roman:romanize 141)))

(define-test test-163
  (assert-equal "CLXIII" (roman:romanize 163)))

(define-test test-402
  (assert-equal "CDII" (roman:romanize 402)))

(define-test test-575
  (assert-equal "DLXXV" (roman:romanize 575)))

(define-test test-911
  (assert-equal "CMXI" (roman:romanize 911)))

(define-test test-1024
  (assert-equal "MXXIV" (roman:romanize 1024)))

(define-test test-3000
  (assert-equal "MMM" (roman:romanize 3000)))

(let ((*print-errors* t)
      (*print-failures* t))
  (run-tests :all :roman-test))
(defpackage #:roman
  (:use #:cl)
  (:export #:romanize))

(in-package #:roman)

(defun romanize (num)
  (format nil "~@r" num))

Community comments

Find this solution interesting? Ask the author a question to learn more.

What can you learn from this solution?

A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?