Personal tools

Roman numerals

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
m (code was running off page)
 
(One intermediate revision by one user not shown)
Line 9: Line 9:
   
 
romanToInt :: String -> Int
 
romanToInt :: String -> Int
romanToInt = fs
+
romanToInt = fst
 
. foldr (\p (t,s) -> if p >= s then (t+p,p) else (t-p,p)) (0,0)
 
. foldr (\p (t,s) -> if p >= s then (t+p,p) else (t-p,p)) (0,0)
 
. map (fromJust . flip lookup (zip "IVXLCDM" [1,5,10,50,100,500,1000]))
 
. map (fromJust . flip lookup (zip "IVXLCDM" [1,5,10,50,100,500,1000]))
 
</haskell>
 
</haskell>
  +
  +
== More-than-one liner ==
  +
  +
[http://www.cs.york.ac.uk/ftpdir/pub/haskell/contrib/Roman.hs A more explanatory program] for conversions in both directions - toRoman and fromRoman.
   
 
== Roman (type-)numerals ==
 
== Roman (type-)numerals ==

Latest revision as of 09:37, 8 June 2009

The system of Roman numerals is a numeral system originating in ancient Rome, and was adapted from Etruscan numerals. The system used in classical antiquity was slightly modified in the Middle Ages to produce the system we use today. It is based on certain letters which are given values as numerals.

Contents

[edit] 1 Oneliner

This is a nearly-completely points-freed expression which evaluates a given Roman numeral as a String to the corresponding Int. The folded function is not points-freed for ease of reading, and it would also need an `if' function which needs separate definition.

import Data.Maybe (fromJust)
 
romanToInt :: String -> Int
romanToInt = fst
                  . foldr (\p (t,s) -> if p >= s then (t+p,p) else (t-p,p)) (0,0)
                  . map (fromJust . flip lookup (zip "IVXLCDM" [1,5,10,50,100,500,1000]))

[edit] 2 More-than-one liner

A more explanatory program for conversions in both directions - toRoman and fromRoman.

[edit] 3 Roman (type-)numerals

The function `roman' here infers the value of the Roman numeral from the type of its first argument, which in turn is left unevaluated, and returns it as an Int.

{-# OPTIONS_GHC -fglasgow-exts #-}
module Romans where
 
class Roman t where
  roman :: t -> Int
 
data O   -- 0
data I a -- 1
data V a -- 5
data X a -- 10
data L a -- 50
data C a -- 100
data D a -- 500
data M a -- 1000
 
instance                Roman O         where roman _ = 0
instance                Roman (I O)     where roman _ = 1
instance                Roman (V O)     where roman _ = 5
instance                Roman (X O)     where roman _ = 10
 
instance Roman (I a) => Roman (I (I a)) where roman _ = roman (undefined :: (I a)) + 1
instance Roman a     => Roman (I (V a)) where roman _ = roman (undefined :: a)     + 4
instance Roman a     => Roman (I (X a)) where roman _ = roman (undefined :: a)     + 9
 
instance Roman (I a) => Roman (V (I a)) where roman _ = roman (undefined :: (I a)) + 5
instance Roman (V a) => Roman (V (V a)) where roman _ = roman (undefined :: (V a)) + 5
 
instance Roman (I a) => Roman (X (I a)) where roman _ = roman (undefined :: (I a)) + 10
instance Roman (V a) => Roman (X (V a)) where roman _ = roman (undefined :: (V a)) + 10
instance Roman (X a) => Roman (X (X a)) where roman _ = roman (undefined :: (X a)) + 10
instance Roman a     => Roman (X (L a)) where roman _ = roman (undefined :: a)     + 40
instance Roman a     => Roman (X (C a)) where roman _ = roman (undefined :: a)     + 90
instance Roman a     => Roman (X (D a)) where roman _ = roman (undefined :: a)     + 490
 
instance Roman a     => Roman (L a)     where roman _ = roman (undefined :: a)     + 50
 
instance Roman (I a) => Roman (C (I a)) where roman _ = roman (undefined :: (I a)) + 100
instance Roman (V a) => Roman (C (V a)) where roman _ = roman (undefined :: (V a)) + 100
instance Roman (X a) => Roman (C (X a)) where roman _ = roman (undefined :: (X a)) + 100
instance Roman (L a) => Roman (C (L a)) where roman _ = roman (undefined :: (L a)) + 100
instance Roman (C a) => Roman (C (C a)) where roman _ = roman (undefined :: (C a)) + 100
instance Roman a     => Roman (C (D a)) where roman _ = roman (undefined :: a)     + 400
instance Roman a     => Roman (C (M a)) where roman _ = roman (undefined :: a)     + 900
 
instance Roman a     => Roman (D a)     where roman _ = roman (undefined :: a)     + 500
 
instance Roman a     => Roman (M a)     where roman _ = roman (undefined :: a)     + 1000
 
-- Example type: XVI ~> X (V (I O)); MCMXCIX ~> M (C (M (X (C (I (X O))))))
 
powersoftwo = [roman (undefined :: (I (I O))),
               roman (undefined :: (I (V O))),
               roman (undefined :: (V (I (I (I O))))),
               roman (undefined :: (X (V (I O)))),
               roman (undefined :: (X (X (X (I (I O)))))),
               roman (undefined :: (L (X (I (V O))))),
               roman (undefined :: (C (X (X (V (I (I (I O)))))))),
               roman (undefined :: (C (C (L (V (I O)))))),
               roman (undefined :: (D (X (I (I O))))),
               roman (undefined :: (M (X (X (I (V O)))))),
               roman (undefined :: (M (M (X (L (V (I (I (I O)))))))))]

[edit] 4 With data constructors

I think there is also some simpler solution using

data RomanDigit a =
     O   -- 0
   | I a -- 1
   | V a -- 5
   | X a -- 10
   | L a -- 50
   | C a -- 100
   | D a -- 500
   | M a -- 1000

if not only an enumeration of digits which can be used in a regular list.