Skip to content

Instantly share code, notes, and snippets.

@shangaslammi
Created October 3, 2011 19:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shangaslammi/1260051 to your computer and use it in GitHub Desktop.
Save shangaslammi/1260051 to your computer and use it in GitHub Desktop.
Roman numerals kata in Haskell
module Roman where
import Data.Tuple
import Data.List
values = [
(1000, 'M'),
(500, 'D'),
(100, 'C'),
(50, 'L'),
(10, 'X'),
(5, 'V'),
(1, 'I') ]
toRoman :: Int -> String
toRoman i = go values where
go ((v,c):_) | v <= i = c : toRoman (i-v)
go ((v,c):(nv,nc):_) | v-nv <= i && v /= 2*nv = nc : c : toRoman (i-v+nv)
go ((v,c):_:(nv,nc):_) | v-nv <= i = nc : c : toRoman (i-v+nv)
go (_:vs) = go vs
go _ = ""
fromRoman :: String -> Maybe Int
fromRoman = fmap (sum . foldr go [] . tails) . sequence . map getVal where
go (a:b:_) acc | a < b = -a:acc where
go (a:_) acc = a : acc
go _ acc = acc
getVal = flip lookup rvalues
rvalues = map swap values
import Roman
import Test.HUnit
testRoman i s = ("test " ++ show i) ~: s ~=? toRoman i
testReverse i s = ("test " ++ s) ~: Just i ~=? fromRoman s
tests = [
(1, "I"),
(2, "II"),
(3, "III"),
(4, "IV"),
(5, "V"),
(6, "VI"),
(7, "VII"),
(8, "VIII"),
(9, "IX"),
(10, "X"),
(11, "XI"),
(12, "XII"),
(13, "XIII"),
(14, "XIV"),
(15, "XV"),
(16, "XVI"),
(17, "XVII"),
(18, "XVIII"),
(19, "XIX"),
(20, "XX"),
(30, "XXX"),
(40, "XL"),
(42, "XLII"),
(50, "L"),
(69, "LXIX"),
(90, "XC"),
(301, "CCCI"),
(423, "CDXXIII"),
(900, "CM"),
(1900, "MCM"),
(1990, "MCMXC"),
(2008, "MMVIII"),
(3297, "MMMCCXCVII"),
(3999, "MMMCMXCIX")
]
main = runTestTT $ test $ forwardTests ++ reverseTests where
forwardTests = map (uncurry testRoman) $ tests
reverseTests = map (uncurry testReverse) $ tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment