rank s = fromMaybe (OtherRank s) maybeRanked where
    (rank, rest)        = span isDigit s
    (scale, certainty)  = span isAlpha rest
    maybeRank           = listToMaybe rank >> return (read rank)
    maybeScale          = lookup (map toLower scale) scales
    maybeCertainty      = lookup certainty certainties
    maybeRanked = liftM3 Ranked maybeRank maybeScale maybeCertainty
    certainties = [("", Nothing), ("?", Just Uncertain), ("*", Just Certain)]
    scales      = abbreviateList [("kyu", Kyu), ("dan", Dan), ("pro", Pro)]
rank s = fromMaybe (OtherRank s) maybeRanked where
    (rank, rest)        = span isDigit s
    (scale, certainty)  = span isAlpha rest
    maybeRank           = listToMaybe rank >> return (read rank)
    maybeScale          = lookup (map toLower scale) scales
    maybeCertainty      = lookup certainty certainties
    maybeRanked = liftM3 Ranked maybeRank maybeScale maybeCertainty
    certainties = [("", Nothing), ("?", Just Uncertain), ("*", Just Certain)]
    scales      = abbreviateList [("kyu", Kyu), ("dan", Dan), ("pro", Pro)]
rank s = fromMaybe (OtherRank s) maybeRanked where
    (rank, rest)        = span isDigit s
    (scale, certainty)  = span isAlpha rest
    maybeRank           = listToMaybe rank >> return (read rank)
    maybeScale          = lookup (map toLower scale) scales
    maybeCertainty      = lookup certainty certainties
    maybeRanked = liftM3 Ranked maybeRank maybeScale maybeCertainty
    certainties = [("", Nothing), ("?", Just Uncertain), ("*", Just Certain)]
    scales      = abbreviateList [("kyu", Kyu), ("dan", Dan), ("pro", Pro)]