roman-numerals 0.4.0.1 → 0.5.0
raw patch · 2 files changed
+80/−66 lines, 2 filesdep +textdep −mtlPVP ok
version bump matches the API change (PVP)
Dependencies added: text
Dependencies removed: mtl
API changes (from Hackage documentation)
+ Text.Numeral.Roman: instance StripPrefix Text
- Text.Numeral.Roman: convertFrom :: (Monoid s, StripPrefix s, Eq s, Ord n, Num n, MonadError String m) => NumeralConfig s n -> s -> m n
+ Text.Numeral.Roman: convertFrom :: (Monoid s, StripPrefix s, Eq s, Ord n, Num n) => NumeralConfig s n -> s -> Maybe n
- Text.Numeral.Roman: fromRoman :: (IsString s, Monoid s, StripPrefix s, Eq s, Ord n, Num n, MonadError String m) => s -> m n
+ Text.Numeral.Roman: fromRoman :: (IsString s, Monoid s, StripPrefix s, Eq s, Ord n, Num n) => s -> Maybe n
Files
- Text/Numeral/Roman.hs +78/−64
- roman-numerals.cabal +2/−2
Text/Numeral/Roman.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE FlexibleContexts+{-# LANGUAGE CPP+ , FlexibleContexts , NoImplicitPrelude , OverloadedStrings , UnicodeSyntax@@ -7,11 +8,10 @@ {-| Parsing and pretty printing of Roman numerals. This module provides functions for parsing and pretty printing Roman-numerals. Because the notation of Roman numerals has varied through-the centuries this package allows for some customisation using a-configuration that is passed to the conversion functions. Exceptions-are dealt with by wrapping the results of conversions in the error-monad.+numerals. Because the notation of Roman numerals has varied through the+centuries this package allows for some customisation using a configuration that+is passed to the conversion functions. Exceptions are dealt with by wrapping the+results of conversions in the error monad. Example: @@ -21,8 +21,8 @@ @ @- \> 'fromRoman' \"MDCCXXIX\" ∷ Either String Integer- Right 1729+ \> 'fromRoman' \"MDCCXXIX\" ∷ Maybe Integer+ Just 1729 @ @@@ -31,8 +31,8 @@ @ @- \> 'fromRoman' \"Bla\" ∷ Either String Integer- Left \"Roman.convertFrom: can't parse\"+ \> 'fromRoman' \"Bla\" ∷ Maybe Integer+ Nothing @ -}@@ -62,47 +62,56 @@ ------------------------------------------------------------------------------- -- from base:+import Control.Monad ( return, mzero ) import Data.Bool ( Bool, otherwise )-import Data.Char ( String ) import Data.Eq ( Eq ) import Data.Function ( ($), flip, on ) import Data.List ( sortBy, null, stripPrefix ) import Data.Maybe ( Maybe(Nothing, Just), maybe ) import Data.Monoid ( Monoid ) import Data.Ord ( Ord, compare )-import Data.String ( IsString, fromString )+import Data.String ( IsString ) import Data.Tuple ( snd )-import Control.Monad ( (>>=), (>>), return, fail )-import Prelude ( Num, (+), (-), fromInteger, error )+import Prelude ( Num, (+), (-), error ) +#if __GLASGOW_HASKELL__ < 700+import Control.Monad ( (>>=), (>>), fail )+import Data.String ( fromString )+import Prelude ( fromInteger )+#endif+ -- from base-unicode-symbols: import Data.Eq.Unicode ( (≡) )-import Data.Function.Unicode ( (∘) )-import Data.Ord.Unicode ( (≥), (≤) ) import Data.Monoid.Unicode ( (∅), (⊕) )+import Data.Ord.Unicode ( (≥), (≤) ) -- from bytestring:-import qualified Data.ByteString as BS+import qualified Data.ByteString as BS ( ByteString+ , isPrefixOf+ , drop, length, null + )+import qualified Data.ByteString.Lazy as BSL ( ByteString+ , isPrefixOf+ , drop, length, null + ) --- from monads-fd:-import Control.Monad.Error ( MonadError, throwError )+-- from text:+import qualified Data.Text as T ( Text, null, stripPrefix )+import qualified Data.Text.Lazy as TL ( Text, null, stripPrefix ) ------------------------------------------------------------------------------- -- Types ------------------------------------------------------------------------------- --- |A configuration with which the 'convertTo' and 'convertFrom'--- functions can be parameterized.+-- |A configuration with which the 'convertTo' and 'convertFrom' functions can+-- be parameterized. data NumeralConfig s n = NC { -- |Symbol to represent the value 0. ncZero ∷ s- -- |A table of symbols and their numerical values. The table- -- must be ordered in descending order of the value of the- -- symbols. If any symbol is the empty string then 'convertFrom'- -- will be ⊥. If any symbol in this table is associated- -- with the value 0 both the 'convertTo' and 'convertFrom'- -- function will be ⊥.+ -- |A table of symbols and their numerical values. The table must be+ -- ordered in descending order of the value of the symbols. If any symbol+ -- is the empty string then 'convertFrom' will be ⊥. , ncTable ∷ [(s, n)] } @@ -117,16 +126,12 @@ , ncTable = sortBy (flip compare `on` snd) ((o, 1) : tab) } + ------------------------------------------------------------------------------- -- Pretty printing ------------------------------------------------------------------------------- --- |Converts a number to a Roman numeral according to the given--- configuration. Numbers which are out of bounds will cause--- exceptions to be thrown. An exception will also be raised if no--- representation is possible with the given configuration. If the--- value of any symbol in the configuration is equal to 0 or a symbol--- is the empty string this function is undefined.+-- |Converts a number to a Roman numeral according to the given configuration. convertTo ∷ Monoid s ⇒ Ord n ⇒ Num n ⇒ NumeralConfig s n → n → s convertTo nc n | n ≡ 0 = ncZero nc@@ -153,39 +158,51 @@ instance StripPrefix BS.ByteString where spNull = BS.null- spStripPrefix p s = let (h, t) = BS.breakSubstring p s- in if spNull h- then Just $ BS.drop (BS.length p) t- else Nothing+ spStripPrefix p s = if p `BS.isPrefixOf` s+ then Just $ BS.drop (BS.length p) s+ else Nothing +instance StripPrefix BSL.ByteString where+ spNull = BSL.null+ spStripPrefix p s = if p `BSL.isPrefixOf` s+ then Just $ BSL.drop (BSL.length p) s+ else Nothing++instance StripPrefix T.Text where+ spNull = T.null+ spStripPrefix = T.stripPrefix++instance StripPrefix TL.Text where+ spNull = TL.null+ spStripPrefix = TL.stripPrefix++ -- |Parses a string as a Roman numeral according to the given--- configuration. An exception will be thrown if the input is not a--- valid numeral.-convertFrom ∷ (Monoid s, StripPrefix s, Eq s, Ord n, Num n, MonadError String m)- ⇒ NumeralConfig s n → s → m n+-- configuration. Result is 'Nothing' if the input is not a valid numeral.+convertFrom ∷ ( Monoid s, StripPrefix s, Eq s+ , Ord n, Num n+ )+ ⇒ NumeralConfig s n → s → Maybe n convertFrom nc s | ncZero nc ≡ s = return 0 | otherwise = do n ← (go 0 (ncTable nc) s) if s ≡ convertTo nc n then return n- else errMsg "invalid Roman numeral"+ else mzero where go n _ x | spNull x = return n- go _ [] _ = errMsg "can't parse"+ go _ [] _ = mzero go n tab@((sym, val) : ts) x = maybe (go n ts x) (go (n + val) tab) $ spStripPrefix sym x- errMsg = throwError ∘ ("Roman.convertFrom: " ⊕) - ------------------------------------------------------------------------------- -- Default Configurations ------------------------------------------------------------------------------- --- |Configuration for Roman numerals as they are commonly used--- today. The value 0 is represented by the empty string. It can be--- interpreted as not writing down a number. This configuration is--- practically limited to the range [1..3999]. Smaller numbers will--- result in empty string. Larger numbers will result in repeated use--- of the \'M\' symbol.+-- |Configuration for Roman numerals as they are commonly used today. The value+-- 0 is represented by the empty string. It can be interpreted as not writing+-- down a number. This configuration is practically limited to the range+-- [1..3999]. Smaller numbers will result in an empty string. Larger numbers+-- will result in repeated use of the \'M\' symbol. modernRoman ∷ (IsString s, Ord n, Num n) ⇒ NumeralConfig s n modernRoman = mkNumConfig ""@@ -204,12 +221,12 @@ , ("M", 1000) ] --- |Configuration for Roman numerals that do not use the rule that a--- lower rank symbol can be placed before a higher rank symbol to--- denote the difference between them. Thus a numeral like \"IV\" will--- not be accepted or generated by this configuration. This--- configuration is practically limited to the range [1..3999]. Larger--- numbers will result in repeated use of the \'M\' symbol.+-- |Configuration for Roman numerals that do not use the rule that a lower rank+-- symbol can be placed before a higher rank symbol to denote the difference+-- between them. Thus a numeral like \"IV\" will not be accepted or generated by+-- this configuration. This configuration is practically limited to the range+-- [1..3999]. Smaller numbers will result in an empty string. Larger numbers+-- will result in repeated use of the \'M\' symbol. simpleRoman ∷ (IsString s, Ord n, Num n) ⇒ NumeralConfig s n simpleRoman = mkNumConfig ""@@ -227,15 +244,12 @@ -- Utility ------------------------------------------------------------------------------- --- |Converts a number to a modern Roman numeral. See 'convertTo' for--- possible exceptions.+-- |Converts a number to a modern Roman numeral. toRoman ∷ (IsString s, Monoid s, Ord n, Num n) ⇒ n → s toRoman = convertTo modernRoman ---- |Parses a string as a modern Roman numeral. See 'convertFrom' for--- possible exceptions.+-- |Parses a string as a modern Roman numeral. fromRoman ∷ ( IsString s, Monoid s, StripPrefix s, Eq s- , Ord n, Num n, MonadError String m- ) ⇒ s → m n+ , Ord n, Num n+ ) ⇒ s → Maybe n fromRoman = convertFrom modernRoman
roman-numerals.cabal view
@@ -1,5 +1,5 @@ name: roman-numerals-version: 0.4.0.1+version: 0.5.0 cabal-version: >= 1.6 build-type: Simple stability: stable@@ -26,7 +26,7 @@ build-depends: base >= 3.0.3.1 && < 4.4 , base-unicode-symbols >= 0.1.1 && < 0.3 , bytestring >= 0.9.1 && < 0.10- , mtl >= 2.0.0.0 && < 2.1+ , text >= 0.11 && < 0.12 exposed-modules: Text.Numeral.Roman ghc-options: -Wall