content: 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"]
  