```⍝   R o m a n   N u m e r a l s     See →notes.roman←

← .()                           ⍝ digit binding:            7 → V.I.I
⍴() ⍺()                       ⍝ Roman ←→ Arabic: C.X.L.I.X ←→ 1.4.9
← ×() ÷() %()                   ⍝ mul div rem
← +() -()                       ⍝ add sub

⍝ Pattern sets:

s p q r ::                                        ⍝ match anything.
n m :: I V X L C D M                          ⍝ match single digit.
k :: absurdus nimius                        ⍝ too small, too big.
i :: nulla                                  ⍝ nothing.
j :: I V X L C D M absurdus nulla nimius    ⍝ any atomic value.

⍝ Auxiliary functions for expanded digit strings:

\()              ⍝ expand (remove subtractive prefixes).
/()              ⍝ compress (apply subtractive prefixes).
←  ∘()              ⍝ expanded digit separator (disables normalisation).

p + q = /(\p ++ \q)          ⍝ Add expanded digit strings.

← ++()                       ⍝ merge strings, preserving order.

p ++ k   = k                 ⍝ special values.
k ++ p   = k
i ++ q   = q
p ++ i   = p

p ++ I   = p∘I               ⍝ First, collect Is, then
I ++ q   = q∘I
p   ++ q∘I = (p ++ q)∘I
p∘I ++ q   = (p ++ q)∘I

p ++ V   = p∘V               ⍝ collect Vs, then
V ++ q   = q∘V
p   ++ q∘V = (p ++ q)∘V
p∘V ++ q   = (p ++ q)∘V

p ++ X   = p∘X               ⍝ collect Xs, then
X ++ q   = q∘X
p   ++ q∘X = (p ++ q)∘X
p∘X ++ q   = (p ++ q)∘X

p ++ L   = p∘L               ⍝ collect Ls, then
L ++ q   = q∘L
p   ++ q∘L = (p ++ q)∘L
p∘L ++ q   = (p ++ q)∘L

p ++ C   = p∘C               ⍝ collect Cs, then
C ++ q   = q∘C
p   ++ q∘C = (p ++ q)∘C
p∘C ++ q   = (p ++ q)∘C

p ++ D   = p∘D               ⍝ collect Ds, then
D ++ q   = q∘D
p   ++ q∘D = (p ++ q)∘D
p∘D ++ q   = (p ++ q)∘D

p ++ M   = p∘M               ⍝ collect Ms.
M ++ q   = q∘M
p   ++ q∘M = (p ++ q)∘M
p∘M ++ q   = (p ++ q)∘M

⍝ Sub
p - q = /(\p -- \q)           ⍝ Subtract expanded digit strings.

← --()                         ⍝ remove common digits.

V -- I = I∘I∘I∘I                       ⍝ sub I
X -- I = V∘I∘I∘I∘I
L -- I = X∘X∘X∘X∘V∘I∘I∘I∘I
C -- I = L∘X∘X∘X∘X∘V∘I∘I∘I∘I
D -- I = C∘C∘C∘C∘L∘X∘X∘X∘X∘V∘I∘I∘I∘I
M -- I = D∘C∘C∘C∘C∘L∘X∘X∘X∘X∘V∘I∘I∘I∘I

X -- V = V                             ⍝ sub V
L -- V = X∘X∘X∘X∘V
C -- V = L∘X∘X∘X∘X∘V
D -- V = C∘C∘C∘C∘L∘X∘X∘X∘X∘V
M -- V = D∘C∘C∘C∘C∘L∘X∘X∘X∘X∘V

L -- X = X∘X∘X∘X                       ⍝ sub X
C -- X = L∘X∘X∘X∘X
D -- X = C∘C∘C∘C∘L∘X∘X∘X∘X
M -- X = D∘C∘C∘C∘C∘L∘X∘X∘X∘X

C -- L = L                             ⍝ sub L
D -- L = C∘C∘C∘C∘L
M -- L = D∘C∘C∘C∘C∘L

D -- C = C∘C∘C∘C                       ⍝ sub C
M -- C = D∘C∘C∘C∘C

M -- D = D∘C∘C∘C∘C                     ⍝ sub D

p∘m -- m = p                             ⍝ subtract multi-digit nos.
p -- q∘m = p -- q -- m
p∘m -- r = (p -- r) ++ m
(p--p)∘m = m

m -- m = nulla                         ⍝ nothing left.
m -- n = absurdus                      ⍝ less than nothing left.

p -- i = p                              ⍝ special values.
i -- q = absurdus
p -- k = absurdus
k -- q = k

⍝ Mul
p × q = /(\p ×× \q)         ⍝ Multiply expanded digit strings.

← ××()                      ⍝ auxiliary function.

p ×× I = p                  ⍝ I × ···
I ×× q = q                  ⍝ ··· × I

V ×× V = X∘X∘V              ⍝ V × ···
V ×× X = L
V ×× L = C∘C∘L
V ×× C = D
V ×× D = M∘M∘D

X ×× V = L                  ⍝ X × ···
X ×× X = C
X ×× L = D
X ×× C = M

L ×× V = C∘C∘L              ⍝ L × ···
L ×× X = D
L ×× L = M∘M∘D

C ×× V = D                  ⍝ C × ···
C ×× X = M

D ×× V = M∘M∘D              ⍝ D × ···

i ×× q = i                  ⍝ special values
p ×× i = i
k ×× q = k
p ×× k = k

p∘m ×× q∘n = (p××q)++(p××n)++(m××q)++(m××n)
p   ×× q∘n = (p××q)++(p××n)
p∘m ×× q   = (p××q)++        (m××q)

p ×× q = nimius             ⍝ not already covered: overflow.

⍝ Intermediate simplification of expanded strings, speeds up multiply:

I∘I∘I∘I∘I =   V
p∘I∘I∘I∘I∘I = p∘V

V∘V =   X
p∘V∘V = p∘X

X∘X∘X∘X∘X =   L
p∘X∘X∘X∘X∘X = p∘L

L∘L =   C
p∘L∘L = p∘C

C∘C∘C∘C∘C =   D
p∘C∘C∘C∘C∘C = p∘D

D∘D =   M
p∘D∘D = p∘M

⍝ Div                                               ⍝ Integer divide.

p ÷ q = /(div(qr(\p; \q)))                      ⍝ div expanded strings.

div() ⋄ div(q; r) = q                           ⍝ extract quotient

⍝ Rem                                               ⍝ Integer remainder.

p % q = /(rem(qr(\p; \q)))                      ⍝ rem expanded strings.

rem() ⋄ rem(q; r) = r                           ⍝ extract remainder

⍝ Auxiliary functions for division:

← ;()                                           ⍝ tuple item separation.

qr() ⋄ qr(p; q) = dv(p; (sh(p; q; ⊥)); nulla)   ⍝ quotient and remainder.

⍝ Long division:

dv() dv'() dv"()                                ⍝ division.

dv  p;  ⊥;     r = nulla; p                     ⍝ dividend too small: done.
dv  p; (q; s); r = dv' r; s; (sb p; q; nulla)
dv' r; s; (p; q) = dv" q; s; (p++(10 r))
dv" r; ⊥;     q  = q; r                         ⍝ finished.
dv" p; q; r      = dv p; q; r

sb() sb'()                                      ⍝ repeated subtraction.

sb  p; q; r      = sb' p; q; r; (p?q)           ⍝ dividend ? subtrahend:
sb' p; q; r; lt  = r; p                         ⍝ p<q:
sb' p; q; r; s   = sb p--q; q; r∘I              ⍝ p≥q:

sh() sh'()                                      ⍝ divisor "shift".

sh  p; q; r      = sh' p; q; r; (p?q)
sh' p; q; r; lt  = r
sh' p; q; r; s   = sh p; (10 q); (q; r)

⍝ Tenfold (note that "10" is a function).

10()                        ⍝ tenfold.

10 I = X
10 V = L
10 X = C
10 L = D
10 C = M
10 D = nimius               ⍝ too big
10 M = nimius               ⍝ too big
10 j = j                    ⍝ ten nothings are still nothing, etc.

10(p∘n) = (10 p)∘(10 n)

⍝  Compare

← ?() ??()                ⍝ compare expanded strings.

p ?  q = (⌽p)??(⌽q)     ⍝ ⌽: compare more significant values first.

m ?? m = eq

I ?? n = lt
m ?? I = gt

V ?? n = lt
m ?? V = gt

X ?? n = lt
m ?? X = gt

L ?? n = lt
m ?? L = gt

C ?? n = lt
m ?? C = gt

D ?? n = lt
m ?? D = gt

M ?? n = lt
m ?? M = gt

p ?? nimius = lt             ⍝ compare with "too big"
nimius ?? q = gt

p ?? absurdus = gt             ⍝ compare with "too small"
absurdus ?? q = lt

p ?? nulla = gt             ⍝ compare with "nothing"
nulla ?? q = lt

m∘p ?? n   = (m??n)∘gt
m   ?? n∘q = (m??n)∘lt
m∘p ?? n∘q = (m??n)∘(p??q)

eq∘q =  q
lt∘q = lt
gt∘q = gt

⍝ Reverse expanded string binding:  ((a∘b)∘c)∘d → a∘(b∘(c∘d))

⌽()
⌽j     = j
⌽(p∘q) = ⌽⌽(p;q)

⌽⌽()
⌽⌽(j;r)   = j∘r
⌽⌽(p∘q;r) = ⌽⌽(p;q∘r)

⍝ Expand (remove subtractive prefixes). See →notes.roman←

\j = j

\I.V = I∘I∘I∘I
\I.X = V∘I∘I∘I∘I
\X.L = X∘X∘X∘X
\X.C = L∘X∘X∘X∘X
\C.D = C∘C∘C∘C
\C.M = D∘C∘C∘C∘C

\p.I.V = \p∘I∘I∘I∘I
\p.I.X = \p∘V∘I∘I∘I∘I
\p.X.L = \p∘X∘X∘X∘X
\p.X.C = \p∘L∘X∘X∘X∘X
\p.C.D = \p∘C∘C∘C∘C
\p.C.M = \p∘D∘C∘C∘C∘C

\p.n = \p∘n

⍝ Compress: replace '∘' with '.' to enable renormalisation.

/j = j
/(p∘n) = (/p).n

⍝ Normalise (per norma)

I.I.I.I =   I.V
p.I.I.I.I = p.I.V

I.V.I   =   V
p.I.V.I   = p.V

V.I.I.I.I =   I.X
p.V.I.I.I.I = p.I.X

I.X.I =   X
p.I.X.I = p.X

V.I.V =   I.X
p.V.I.V = p.I.X

X.X.X.X =   X.L
p.X.X.X.X = p.X.L

X.L.X  =   L
p.X.L.X  = p.L

X.X.X.X.I.X =   X.L.I.X
p.X.X.X.X.I.X = p.X.L.I.X

L.X.L =   X.C
p.L.X.L = p.X.C

X.C.X =   C
p.X.C.X = p.C

C.C.C.C =   C.D
p.C.C.C.C = p.C.D

C.D.C =   D
p.C.D.C = p.D

D.C.C.C.C =   C.M
p.D.C.C.C.C = p.C.M

D.C.D =   C.M
p.D.C.D = p.C.M

C.M.C =   M
p.C.M.C = p.M

V.V =   X
p.V.V = p.X

L.L =   C
p.L.L = p.C

D.D =   M
p.D.D = p.M

M.M.M.M = nimius          ⍝ overflow (too big)

p.i = p               ⍝ special values.
i.q = q
p.k = k
k.q = k

⍝ Roman from Arabic     1 ·· 3,999

⍴⍴()          ⍝ Auxiliary function

⍴⍴(0∘I) = nulla                     ⍝⍝⍝⍝
⍴⍴(1∘I) = I                         ⍝
⍴⍴(2∘I) = I.I                       ⍝
⍴⍴(3∘I) = I.I.I                     ⍝
⍴⍴(4∘I) = I.V                       ⍝
⍴⍴(5∘I) = V                         ⍝
⍴⍴(6∘I) = V.I                       ⍝
⍴⍴(7∘I) = V.I.I                     ⍝
⍴⍴(8∘I) = V.I.I.I                   ⍝
⍴⍴(9∘I) = I.X                       ⍝
⍝  1 ·· 9
⍴⍴(p.0∘I) =  ⍴⍴(p∘X)                ⍝
⍴⍴(p.1∘I) = (⍴⍴(p∘X)).I             ⍝
⍴⍴(p.2∘I) = (⍴⍴(p∘X)).I.I           ⍝
⍴⍴(p.3∘I) = (⍴⍴(p∘X)).I.I.I         ⍝
⍴⍴(p.4∘I) = (⍴⍴(p∘X)).I.V           ⍝
⍴⍴(p.5∘I) = (⍴⍴(p∘X)).V             ⍝
⍴⍴(p.6∘I) = (⍴⍴(p∘X)).V.I           ⍝
⍴⍴(p.7∘I) = (⍴⍴(p∘X)).V.I.I         ⍝
⍴⍴(p.8∘I) = (⍴⍴(p∘X)).V.I.I.I       ⍝
⍴⍴(p.9∘I) = (⍴⍴(p∘X)).I.X        ⍝⍝⍝⍝

⍴⍴(1∘X) = X                      ⍝⍝⍝⍝
⍴⍴(2∘X) = X.X                       ⍝
⍴⍴(3∘X) = X.X.X                     ⍝
⍴⍴(4∘X) = X.L                       ⍝
⍴⍴(5∘X) = L                         ⍝
⍴⍴(6∘X) = L.X                       ⍝
⍴⍴(7∘X) = L.X.X                     ⍝
⍴⍴(8∘X) = L.X.X.X                   ⍝
⍴⍴(9∘X) = X.C                       ⍝
⍝  1.0 ·· 9.0
⍴⍴(p.0∘X) =  ⍴⍴(p∘C)                ⍝
⍴⍴(p.1∘X) = (⍴⍴(p∘C)).X             ⍝
⍴⍴(p.2∘X) = (⍴⍴(p∘C)).X.X           ⍝
⍴⍴(p.3∘X) = (⍴⍴(p∘C)).X.X.X         ⍝
⍴⍴(p.4∘X) = (⍴⍴(p∘C)).X.L           ⍝
⍴⍴(p.5∘X) = (⍴⍴(p∘C)).L             ⍝
⍴⍴(p.6∘X) = (⍴⍴(p∘C)).L.X           ⍝
⍴⍴(p.7∘X) = (⍴⍴(p∘C)).L.X.X         ⍝
⍴⍴(p.8∘X) = (⍴⍴(p∘C)).L.X.X.X       ⍝
⍴⍴(p.9∘X) = (⍴⍴(p∘C)).X.C        ⍝⍝⍝⍝

⍴⍴(1∘C) = C                      ⍝⍝⍝⍝
⍴⍴(2∘C) = C.C                       ⍝
⍴⍴(3∘C) = C.C.C                     ⍝
⍴⍴(4∘C) = C.D                       ⍝
⍴⍴(5∘C) = D                         ⍝
⍴⍴(6∘C) = D.C                       ⍝
⍴⍴(7∘C) = D.C.C                     ⍝
⍴⍴(8∘C) = D.C.C.C                   ⍝
⍴⍴(9∘C) = C.M                       ⍝
⍝  1.0.0 ·· 9.0.0
⍴⍴(p.0∘C) =  ⍴⍴(p∘M)                ⍝
⍴⍴(p.1∘C) = (⍴⍴(p∘M)).C             ⍝
⍴⍴(p.2∘C) = (⍴⍴(p∘M)).C.C           ⍝
⍴⍴(p.3∘C) = (⍴⍴(p∘M)).C.C.C         ⍝
⍴⍴(p.4∘C) = (⍴⍴(p∘M)).C.D           ⍝
⍴⍴(p.5∘C) = (⍴⍴(p∘M)).D             ⍝
⍴⍴(p.6∘C) = (⍴⍴(p∘M)).D.C           ⍝
⍴⍴(p.7∘C) = (⍴⍴(p∘M)).D.C.C         ⍝
⍴⍴(p.8∘C) = (⍴⍴(p∘M)).D.C.C.C       ⍝
⍴⍴(p.9∘C) = (⍴⍴(p∘M)).C.M        ⍝⍝⍝⍝

⍴⍴(1∘M) = M                      ⍝⍝⍝⍝
⍴⍴(2∘M) = M.M                       ⍝  1.0.0.0 ·· 3.0.0.0
⍴⍴(3∘M) = M.M.M                  ⍝⍝⍝⍝

⍴⍴(p) = nimius                 ⍝⍝⍝⍝  otherwise: too big

⍝ Arabic from Roman

⍺⍺()                      ⍝ Auxiliary function.
← <+>()                       ⍝ add multi-digit Arabic numbers.

a b :: 0 1 2 3 4 5 6 7 8 9      ⍝ Arabic digits

⍺ r = ⍺⍺(\r)

⍺⍺ i =       0
⍺⍺ I =       1
⍺⍺ V =       5
⍺⍺ X =     1.0
⍺⍺ L =     5.0
⍺⍺ C =   1.0.0
⍺⍺ D =   5.0.0
⍺⍺ M = 1.0.0.0

⍺⍺ nulla    = 0
⍺⍺ nimius   = too_big
⍺⍺ absurdus = negative

⍺⍺(p∘m) = ⍺⍺p <+> ⍺⍺m

a <+> 0 = a
0 <+> b = b

1 <+> 1 = 2
2 <+> 1 = 3
3 <+> 1 = 4
4 <+> 1 = 5
5 <+> 1 = 6
6 <+> 1 = 7
7 <+> 1 = 8
8 <+> 1 = 9

p.a <+>   b =       p.(a<+>b)
p.a <+> q.b = (p<+>q).(a<+>b)

⍝ Equivalence functions

← =() ≡()           ⍝ reduction equivalence/trace

⍝ Test Cases
⍝
⍝                 I.I.I.I -> I.V                ⍝ normalisation
⍝               I.I.I.I.I -> V
⍝             I.I.I.I.I.I -> V.I
⍝
⍝             I+I+I+I+I+I -> V.I                ⍝ addition
⍝                 I.V + I -> V
⍝           V.I.I + V.I.I -> X.I.V
⍝               I.X + I.X -> X.V.I.I.I
⍝       X.L.I.X + X.L.I.X -> X.C.V.I.I.I
⍝                 M+M+M+M -> nimius
⍝
⍝                 X.X - I -> X.I.X              ⍝ subtraction.
⍝                 V.I - V -> I
⍝     X-I.I.I.I.I.I.I.I.I -> I
⍝               X.X - I.I -> X.V.I.I.I
⍝             X.I.V - V.I -> V.I.I.I
⍝                 C.I - V -> X.C.V.I
⍝                 M.M - I -> M.C.M.X.C.I.X
⍝                   X-V-V -> nulla
⍝                 X-V-V-V -> absurdus
⍝
⍝           X.I.V × X.I.V -> C.X.C.V.I          ⍝ multiplication
⍝                   X×X×X -> M
⍝                 X×X×X×X -> nimius
⍝             I.I × nulla -> nulla
⍝
⍝                   V ÷ I -> V                  ⍝ division
⍝                   C ÷ X -> X
⍝               X.I ÷ I.I -> V
⍝           C.X.L.V ÷ V.I -> X.X.I.V
⍝                   V ÷ X -> nulla
⍝               X.I.I ÷ V -> I.I
⍝
⍝           C.X.L.V % V.I -> I                  ⍝ remainder
⍝                   X % V -> nulla
⍝                   V % X -> V
⍝               X.I.I % V -> I.I
⍝
⍝               ⍴ 1.9.9.9 -> M.C.M.X.C.I.X      ⍝ Roman from Arabic
⍝               ⍴ 3.9.9.9 -> M.M.M.C.M.X.C.I.X
⍝               ⍴ 4.0.0.0 -> nimius             ⍝ (number too big)
⍝
⍝         ⍺ M.C.M.X.C.I.X -> 1.9.9.9            ⍝ Arabic from Roman
⍝     ⍺ M.M.M.C.M.X.C.I.X -> 3.9.9.9
⍝
⍝                  ⍺⍴ 4.9 -> 4.9                ⍝ round trip.
⍝          ⍴⍺ C.M.X.C.I.X -> C.M.X.C.I.X        ⍝   ..   ..
⍝          ⍴⍺ C.D.X.L.I.V -> C.D.X.L.I.V        ⍝   ..   ..
⍝
⍝         M + I.X × C.X.I -> M.C.M.X.C.I.X      ⍝ misc
⍝
⍝   Back to: Contents
```