-- romanValue :: String -> Int on romanValue(s) script roman property mapping : [["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]] -- Value of first Roman glyph + value of remaining glyphs -- toArabic :: [Char] -> Int on toArabic(xs) script transcribe -- If this glyph:value pair matches the head of the list -- return the value and the tail of the list -- transcribe :: (String, Number) -> Maybe (Number, [String]) on |λ|(lstPair) set lstR to characters of (item 1 of lstPair) if isPrefixOf(lstR, xs) then -- Value of this matching glyph, with any remaining glyphs {item 2 of lstPair, drop(length of lstR, xs)} else {} end if end |λ| end script if length of xs > 0 then set lstParse to concatMap(transcribe, mapping) (item 1 of lstParse) + toArabic(item 2 of lstParse) else 0 end if end toArabic end script toArabic(characters of s) of roman end romanValue -- TEST ----------------------------------------------------------------------- on run map(romanValue, {"MCMXC", "MDCLXVI", "MMVIII"}) --> {1990, 1666, 2008} end run -- GENERIC FUNCTIONS ---------------------------------------------------------- -- concatMap :: (a -> [b]) -> [a] -> [b] on concatMap(f, xs) set lst to {} set lng to length of xs tell mReturn(f) repeat with i from 1 to lng set lst to (lst & |λ|(item i of xs, i, xs)) end repeat end tell return lst end concatMap -- drop :: Int -> a -> a on drop(n, a) if n < length of a then if class of a is text then text (n + 1) thru -1 of a else items (n + 1) thru -1 of a end if else {} end if end drop -- isPrefixOf :: [a] -> [a] -> Bool on isPrefixOf(xs, ys) if length of xs = 0 then true else if length of ys = 0 then false else set {x, xt} to uncons(xs) set {y, yt} to uncons(ys) (x = y) and isPrefixOf(xt, yt) end if end if end isPrefixOf -- map :: (a -> b) -> [a] -> [b] on map(f, xs) tell mReturn(f) set lng to length of xs set lst to {} repeat with i from 1 to lng set end of lst to |λ|(item i of xs, i, xs) end repeat return lst end tell end map -- Lift 2nd class handler function into 1st class script wrapper -- mReturn :: Handler -> Script on mReturn(f) if class of f is script then f else script property |λ| : f end script end if end mReturn -- uncons :: [a] -> Maybe (a, [a]) on uncons(xs) if length of xs > 0 then {item 1 of xs, rest of xs} else missing value end if end uncons