39 lines
1.2 KiB
Haskell
39 lines
1.2 KiB
Haskell
import qualified Data.Map.Strict as M (Map, fromList, lookup)
|
||
import Data.Maybe (isNothing, isJust, fromJust, catMaybes)
|
||
import Data.List (mapAccumL)
|
||
|
||
mapRoman :: M.Map String Int
|
||
mapRoman =
|
||
M.fromList
|
||
[ ("M", 1000)
|
||
, ("CM", 900)
|
||
, ("D", 500)
|
||
, ("CD", 400)
|
||
, ("C", 100)
|
||
, ("XC", 90)
|
||
, ("L", 50)
|
||
, ("XL", 40)
|
||
, ("X", 10)
|
||
, ("IX", 9)
|
||
, ("V", 5)
|
||
, ("IV", 4)
|
||
, ("I", 1)
|
||
]
|
||
|
||
fromRoman :: String -> Int
|
||
fromRoman s =
|
||
let value k = M.lookup k mapRoman
|
||
in sum . catMaybes . snd $
|
||
mapAccumL
|
||
(\mi (l, r, i) ->
|
||
let mValue = value [l, r] -- mapRoman lookup of [left, right] Chars
|
||
(lastPair, pairValue)
|
||
| isJust mValue = (Just i, mValue) -- Pair match: index updated
|
||
| isNothing mi || i - fromJust mi > 1 = (mi, value [l])
|
||
| otherwise = (mi, Nothing) -- Left Char was counted in pair
|
||
in (lastPair, pairValue))
|
||
Nothing -- Accumulator – maybe Index to last matched Char pair
|
||
(zip3 s (tail s ++ " ") [0 ..]) -- Indexed character pairs
|
||
|
||
main :: IO ()
|
||
main = print $ fromRoman <$> ["MDCLXVI", "MCMXC", "MMVIII", "MMXVI", "MMXVII"]
|