Skip to content

Instantly share code, notes, and snippets.

@davidallsopp
Last active February 8, 2017 14:26
Show Gist options
  • Save davidallsopp/ee1c52a32ed9da393529 to your computer and use it in GitHub Desktop.
Save davidallsopp/ee1c52a32ed9da393529 to your computer and use it in GitHub Desktop.
Haskell version of the Roman numeral converter, using unfold. Taken from https://www.reddit.com/r/programming/comments/658ys/how_to_recognise_a_good_programmer/c02vm1j. There is a code walkthrough at http://billmill.org/roman.html. See also Scala version at https://gist.github.com/davidallsopp/6711935 and reverse program (roman numeral parser) i…
import Data.List (find, unfoldr)
import Control.Arrow (second)
import Control.Applicative ((<$>)) -- for second version
numerals :: [(String, Int)]
numerals = [("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)]
romanize :: Int -> String
romanize = concat . unfoldr next
where next x = fmap (second (x-)) $ find ((<= x) . snd) numerals
-- hlint recommends <$> rather than fmap:
romanize2 :: Int -> String
romanize2 = concat . unfoldr next
where next x = second (x-) <$> find ((<= x) . snd) numerals
@davidallsopp
Copy link
Author

davidallsopp commented Jun 13, 2015

Explanatory types:

concat :: [[a]] -> [a]
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
snd :: (a, b) -> b
find :: (a -> Bool) -> [a] -> Maybe a
second :: Arrow a => a b c -> a (d, b) (d, c) -- in this case, apply a function to the second element of a tuple, preserving the first element

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment