Convert roman to arabic

I started to teach myself Haskell recently. Here is some code I wrote to convert a roman numeral into an arabic numeral:

import Control.Arrow ((>>>))
import Data.Maybe (fromJust)

fromRoman :: String -> Int
fromRoman = translateFromRoman >>> applyNegationRule >>> sum

translateFromRoman :: String -> [Int]
translateFromRoman = map (\r -> fromJust \$ lookup r [('I',1),('V',5),('X',10),('L',50),('C',100),('D',500),('M',1000)])

applyNegationRule :: [Int] -> [Int]
applyNegationRule [x]      = [x]
applyNegationRule (x:y:xs) = (if x < y then -x else x) : applyNegationRule (y:xs)


I like it quite a bit. But some questions remain. First of all I never (at least I can't remember) came across (>>>) in other code so far. Everyone seems to use:

fromRoman :: String -> Int
fromRoman = sum . applyNegationRule . translateFromRoman


It produces the same output, but for me as someone used to read from top left to bottom right the first variant is just more readable. You could also write it like this:

fromRoman :: String -> Int
fromRoman = translateFromRoman
>>> applyNegationRule
>>> sum


To make it even more text like readable. So where's the catch?

Another question arising from this code is: Should I define the functions translateFromRoman and applyNegationRule in fromRoman ... where? Again I see it quite a lot but IMHO it also lacks readability. At the moment readability is one of the most important metrics for me to determine code quality.

And last but note least: Am I doing something bad in translateFromRoman and applyNegationRule or are there some better (faster/shorter or ofcourse more readable) alternatives?

• You could watch this video for inspiration. Sep 9 '15 at 11:12
• @mkrieger1 Can you elaborate on what kind of inspiration I should get from watching the video? For me my code is easier to read than the code in the video. The guy even states: "One really nasty way to generate integers from roman numbers." at the end of the video. To be clear I have working code and I'm looking for non nasty ways. Sep 10 '15 at 5:53
• I just remembered having seen this video some time ago and didn't want it to go unnoticed. I didn't mean to say that what is shown in the video is superior, only that it may open up some alternative views. Sep 10 '15 at 9:22

Since the Roman numerals are fixed and known in advance, it would be more efficient to write:

translateRomanDigit :: Char -> Int
translateRomanDigit 'I' = 1
translateRomanDigit 'V' = 5
...

translateFromRoman = map translateRomanDigit


The compiler can implement translateRomanDigit as a jump table or as a binary search. Using lookup will always perform a linear search.

As for >>> vs . - there should be no difference except that >>> requires you to import Control.Arrow whereas . is provided for in the Prelude.

• I think you're right about translateFromRomanDigit it even adds two benefits. First of all it makes translateFromRoman way more readable and it also gets rid of the Maybe type. Sep 10 '15 at 6:12
• According to this answer on SO there is a difference between >>> and . namely the number of reduction steps is not always the same. Sep 10 '15 at 6:22