45 lines
1.2 KiB
Haskell
45 lines
1.2 KiB
Haskell
module Main where
|
|
|
|
------------------------
|
|
-- DECODER FUNCTION --
|
|
------------------------
|
|
|
|
decodeDigit :: Char -> Int
|
|
decodeDigit 'I' = 1
|
|
decodeDigit 'V' = 5
|
|
decodeDigit 'X' = 10
|
|
decodeDigit 'L' = 50
|
|
decodeDigit 'C' = 100
|
|
decodeDigit 'D' = 500
|
|
decodeDigit 'M' = 1000
|
|
decodeDigit _ = error "invalid digit"
|
|
|
|
-- We process a Roman numeral from right to left, digit by digit, adding the value.
|
|
-- If a digit is lower than the previous then its value is negative.
|
|
-- The first digit is always positive.
|
|
|
|
decode roman = decodeRoman startValue startValue rest
|
|
where
|
|
(first:rest) = reverse roman
|
|
startValue = decodeDigit first
|
|
|
|
decodeRoman :: Int -> Int -> [Char] -> Int
|
|
decodeRoman lastSum _ [] = lastSum
|
|
decodeRoman lastSum lastValue (digit:rest) = decodeRoman updatedSum digitValue rest
|
|
where
|
|
digitValue = decodeDigit digit
|
|
updatedSum = (if digitValue < lastValue then (-) else (+)) lastSum digitValue
|
|
|
|
------------------
|
|
-- TEST SUITE --
|
|
------------------
|
|
|
|
main = do
|
|
test "MCMXC" 1990
|
|
test "MMVIII" 2008
|
|
test "MDCLXVI" 1666
|
|
|
|
test roman expected = putStrLn (roman ++ " = " ++ (show (arabic)) ++ remark)
|
|
where
|
|
arabic = decode roman
|
|
remark = " (" ++ (if arabic == expected then "PASS" else ("FAIL, expected " ++ (show expected))) ++ ")"
|