blob: 9b556fd373018a54ed096979f6544a5b2cf9f322 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
;;; roman-numerals.el --- roman-numerals Exercise (exercism)
;;; Commentary:
;;; Code:
(require 'cl-macs)
(defun rn/unfold (fn x)
(let ((res (funcall fn x)))
(when (car res)
(cons (car res) (rn/unfold fn (cdr res))))))
(defun rn/decimal-digits (number)
"Return the decimal digits of NUMBER as a little-endian list."
(rn/unfold (lambda (x)
(when (> x 0)
(cons (% x 10) (/ x 10)))) number))
(defun rn/zip (l1 l2)
(when (and l1 l2)
(cons (cons (car l1) (car l2))
(rn/zip (cdr l1) (cdr l2)))))
(defun rn/roman-digit (number symbols)
(cl-destructuring-bind (one five ten) symbols
(cond
((eql 0 number) '())
((eql 1 number) (list one))
((eql 2 number) (list one one))
((eql 3 number) (list one one one))
((eql 4 number) (list one five))
((eql 5 number) (list five))
((eql 6 number) (list five one))
((eql 7 number) (list five one one))
((eql 8 number) (list five one one one))
((eql 9 number) (list one ten))
((eql 10 number) (list ten)))))
(defvar rn/roman-symbols
'(("I" "V" "X")
("X" "L" "C")
("C" "D" "M")
("M" nil nil)))
(defun to-roman (number)
(when (> number 3000)
(error 'number-too-big))
(let* ((decimal-digits (rn/decimal-digits number))
(roman-digits
(mapcar (lambda (digit_syms)
(rn/roman-digit (car digit_syms) (cdr digit_syms)))
(rn/zip decimal-digits rn/roman-symbols))))
(apply 'concat (mapcan 'identity (reverse roman-digits)))))
(provide 'roman-numerals)
;;; roman-numerals.el ends here
|