packages feed

quantities 0.3.0 → 0.4.0

raw patch · 10 files changed

+130/−89 lines, 10 filesdep ~Globdep ~doctestdep ~processnew-component:exe:quantities

Dependency ranges changed: Glob, doctest, process, regex-compat

Files

CHANGES.md view
@@ -1,6 +1,16 @@ quantities changelog ==================== +0.4 (unreleased)+----------------++- Changed type of `Quantity` to `Quantity a`, where `a` is the type of the+  magnitude. Note that `a` should be an instance of `Floating` to get the most+  out of the available operations on quantities.+- Added an executable that is an interface to `fromString`+- Can use " per " as a synonym for "=>" in `fromString`++ 0.3 (4-15-2014) ---------------- 
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2014, John David Reaver+Copyright (c) 2014-2015, John David Reaver All rights reserved.  Redistribution and use in source and binary forms, with or without
library/Data/Quantities/Constructors.hs view
@@ -7,7 +7,7 @@ import Data.Quantities.ExprParser (parseExprQuant)  -- | Default set of definitions that come predefined.-defaultDefinitions :: Either QuantityError Definitions+defaultDefinitions :: Either (QuantityError Double) Definitions defaultDefinitions = readDefinitions defaultDefString  -- $setup@@ -25,7 +25,7 @@ -- -- This function also supports unit conversions, by placing \"=>\" in between -- two valid expressions. This behavior is undefined (and returns a--- ScalingFactorError) if the quantity to be converted to has a magnitude.+-- 'ScalingFactorError') if the quantity to be converted to has a magnitude. -- -- >>> fromString "min => s" -- Right 60.0 second@@ -40,7 +40,7 @@ -- Right 1.0 meter ** 2 -- >>> fromString "m ** (2s)" -- Left (ParserError "Used non-dimensionless exponent in ( Right 1.0 meter ) ** ( Right 2.0 second )")-fromString :: String -> Either QuantityError Quantity+fromString :: String -> Either (QuantityError Double) (Quantity Double) fromString s = case defaultDefinitions of                     (Right d) -> parseExprQuant d s                     (Left d)  -> Left d@@ -53,7 +53,7 @@ -- >>> let myFromString = fromString' d -- >>> myFromString "25 my_unit" -- Right 25.0 my_unit-fromString' :: Definitions -> String -> Either QuantityError Quantity+fromString' :: Definitions -> String -> Either (QuantityError Double) (Quantity Double) fromString' = parseExprQuant  @@ -61,5 +61,5 @@ -- -- >>> unitsFromString "N * s" -- Right newton second-unitsFromString :: String -> Either QuantityError CompoundUnit+unitsFromString :: String -> Either (QuantityError Double) CompoundUnit unitsFromString = fmap units . fromString
library/Data/Quantities/Convert.hs view
@@ -15,7 +15,8 @@ -- -- >>> convert <$> fromString "m" <*> unitsFromString "ft" -- Right (Right 3.280839895013123 foot)-convert :: Quantity -> CompoundUnit -> Either QuantityError Quantity+convert :: (Fractional a) => Quantity a -> CompoundUnit ->+           Either (QuantityError a) (Quantity a) convert q us   | hq /= hus = Left  $ DifferentDefinitionsError (units q) us   | otherwise = convert' (defs us) q us@@ -27,15 +28,16 @@ -- -- >>> convertBase <$> fromString "newton" -- Right 1000.0 gram meter / second ** 2-convertBase :: Quantity -> Quantity+convertBase :: (Fractional a) => Quantity a -> Quantity a convertBase x = convertBase' (defs' x) x   -- | Convert quantity to given units.-convert' :: Definitions -> Quantity -> CompoundUnit -> Either QuantityError Quantity+convert' :: (Fractional a) => Definitions -> Quantity a -> CompoundUnit ->+            Either (QuantityError a) (Quantity a) convert' d q us'   | dimq /= dimus = Left  $ DimensionalityError (CompoundUnit d dimq) (CompoundUnit d dimus)-  | otherwise     = Right $ Quantity (mb/mb') us'+  | otherwise     = Right $ Quantity (mb / realToFrac mb') us'   where mb    = magnitude $ convertBase' d q         mb'   = magnitude $ toBase d (sUnits us')         dimq  = dimensionality' d (units' q)@@ -44,19 +46,19 @@   -- | Convert a quantity to its base units.-convertBase' :: Definitions -> Quantity -> Quantity-convertBase' d (Quantity m us) = Quantity (m*mb) ub+convertBase' :: (Fractional a) => Definitions -> Quantity a -> Quantity a+convertBase' d (Quantity m us) = Quantity (m * realToFrac mb) ub   where (Quantity mb ub) = toBase d (sUnits us)   -- | Converts a composite unit to its base quantity-toBase :: Definitions -> [SimpleUnit] -> Quantity+toBase :: Definitions -> [SimpleUnit] -> Quantity Double toBase d = foldr (multiplyQuants . simpleToBase d) unityQuant   where unityQuant = Quantity 1 (CompoundUnit d [])   -- | Converts a simple unit to its base quantity.-simpleToBase :: Definitions -> SimpleUnit -> Quantity+simpleToBase :: Definitions -> SimpleUnit -> Quantity Double simpleToBase d (SimpleUnit sym pre pow) = Quantity m (CompoundUnit d us)   where (m', u') = bases d M.! sym         us = map (\(SimpleUnit s p pow') -> SimpleUnit s p (pow*pow')) u'@@ -67,7 +69,7 @@ -- -- >>> dimensionality <$> fromString "newton" -- Right [length] [mass] / [time] ** 2-dimensionality :: Quantity -> CompoundUnit+dimensionality :: Quantity a -> CompoundUnit dimensionality q = CompoundUnit (defs' q) dimUnits   where dimUnits = dimensionality' (defs' q) (units' q) @@ -82,18 +84,20 @@  -- | Adds two quantities. Second quantity is converted to units of -- first quantity.-addQuants :: Quantity -> Quantity -> Either QuantityError Quantity+addQuants :: (Fractional a) => Quantity a -> Quantity a ->+             Either (QuantityError a) (Quantity a) addQuants = linearQuants (+)   -- | Subtract two quantities. Second quantity is converted to units of -- first quantity.-subtractQuants :: Quantity -> Quantity -> Either QuantityError Quantity+subtractQuants :: (Fractional a) => Quantity a -> Quantity a ->+                  Either (QuantityError a) (Quantity a) subtractQuants = linearQuants (-)  -- | Helper function used in addQuants and subtractQuants.-linearQuants :: (Double -> Double -> Double) -> Quantity -> Quantity-                -> Either QuantityError Quantity+linearQuants :: (Fractional a) => (a -> a -> a) -> Quantity a -> Quantity a+                -> Either (QuantityError a) (Quantity a) linearQuants f (Quantity m1 u1) q2 = case q of   (Right q') -> Right $ Quantity (f m1 (magnitude q')) u1   (Left err) -> Left err
library/Data/Quantities/Data.hs view
@@ -56,34 +56,33 @@   -- | Combination of magnitude and units.-data Quantity = Quantity { magnitude :: Double-                           -- ^ Numerical magnitude of quantity.-                           ---                           -- >>> magnitude <$> fromString "100 N * m"-                           -- Right 100.0-                         , units     :: CompoundUnit-                           -- ^ Units associated with quantity.-                           ---                           -- >>> units <$> fromString "3.4 m/s^2"-                           -- Right meter / second ** 2-                         } deriving (Ord)+data Quantity a = Quantity+  { magnitude :: a            -- ^ Numerical magnitude of quantity.+                              --+                              -- >>> magnitude <$> fromString "100 N * m"+                              -- Right 100.0+  , units     :: CompoundUnit -- ^ Units associated with quantity.+                              --+                              -- >>> units <$> fromString "3.4 m/s^2"+                              -- Right meter / second ** 2+  } deriving (Ord)   -- | Convenience function to extract SimpleUnit collection from Quantity's -- CompoundUnit.-units' :: Quantity -> [SimpleUnit]+units' :: Quantity a -> [SimpleUnit] units' = sUnits . units  -- | Convenience function to extract Definitions from Quantity's CompoundUnit.-defs' :: Quantity -> Definitions+defs' :: Quantity a -> Definitions defs' = defs . units -instance Show Quantity where+instance (Show a) => Show (Quantity a) where   show (Quantity m us) = show m ++ " " ++ show us   -- | Convenience function to make quantity with no definitions.-baseQuant :: Double -> [SimpleUnit] -> Quantity+baseQuant :: a -> [SimpleUnit] -> Quantity a baseQuant m us = Quantity m (CompoundUnit emptyDefinitions us)  -- | Sort units but put negative units at end.@@ -91,31 +90,31 @@ showSort c = pos ++ neg   where (pos, neg) = partition (\q -> power q > 0) c -instance Eq Quantity where+instance (Eq a) => Eq (Quantity a) where   (Quantity m1 u1) == (Quantity m2 u2) = m1 == m2 && sort (sUnits u1) == sort (sUnits u2)   -- | Custom error type-data QuantityError = UndefinedUnitError String-                     -- ^ Used when trying to parse an undefined unit.-                   | DimensionalityError CompoundUnit CompoundUnit-                     -- ^ Used when converting units that do not have the same-                     -- dimensionality (example: convert meter to second).-                   | UnitAlreadyDefinedError String-                     -- ^ Used internally when defining units and a unit is-                     -- already defined.-                   | PrefixAlreadyDefinedError String-                     -- ^ Used internally when defining units and a prefix is-                     -- already defined.-                   | ParserError String-                     -- ^ Used when a string cannot be parsed.-                   | DifferentDefinitionsError CompoundUnit CompoundUnit-                     -- ^ Used when two quantities come from different-                     -- Definitions.-                   | ScalingFactorError Quantity-                     -- ^ Used when a scaling factor is present in a unit-                     -- conversion.-                   deriving (Show, Eq)+data QuantityError a = UndefinedUnitError String+                       -- ^ Used when trying to parse an undefined unit.+                     | DimensionalityError CompoundUnit CompoundUnit+                       -- ^ Used when converting units that do not have the same+                       -- dimensionality (example: convert meter to second).+                     | UnitAlreadyDefinedError String+                       -- ^ Used internally when defining units and a unit is+                       -- already defined.+                     | PrefixAlreadyDefinedError String+                       -- ^ Used internally when defining units and a prefix is+                       -- already defined.+                     | ParserError String+                       -- ^ Used when a string cannot be parsed.+                     | DifferentDefinitionsError CompoundUnit CompoundUnit+                       -- ^ Used when two quantities come from different+                       -- Definitions.+                     | ScalingFactorError (Quantity a)+                       -- ^ Used when a scaling factor is present in a unit+                       -- conversion.+                     deriving (Show, Eq)   -- | Useful for monadic computations with 'QuantityError's. Some examples:@@ -134,10 +133,10 @@ -- >   convertBase x -- -- Returns @Left (UndefinedUnitError "BADUNIT")@-type QuantityComputation = Either QuantityError+type QuantityComputation a = Either (QuantityError a)  -- | Combines equivalent units and removes units with powers of zero.-reduceUnits :: Quantity -> Quantity+reduceUnits :: Quantity a -> Quantity a reduceUnits q = q { units = newUnits }   where newUnits = (units q) { sUnits = reduceUnits' (units' q) } @@ -166,21 +165,21 @@ invertSimpleUnit (SimpleUnit s pr p) = SimpleUnit s pr (-p)  -- | Multiplies two quantities.-multiplyQuants :: Quantity -> Quantity -> Quantity+multiplyQuants :: (Num a) => Quantity a -> Quantity a -> Quantity a multiplyQuants x y = reduceUnits $ Quantity mag newUnits   where mag      = magnitude x * magnitude y         newUnits = (units x) { sUnits = units' x ++ units' y }  -- | Divides two quantities.-divideQuants :: Quantity -> Quantity -> Quantity+divideQuants :: (Fractional a) => Quantity a -> Quantity a -> Quantity a divideQuants x y = reduceUnits $ Quantity mag newUnits   where mag      = magnitude x / magnitude y         newUnits = (units x) { sUnits = units' x ++ invertUnits (units' y) } --- | Exponentiates a quantity with a double.-exptQuants :: Quantity -> Double -> Quantity+-- | Exponentiates a quantity with an integer+exptQuants :: (Real a, Floating a) => Quantity a -> a -> Quantity a exptQuants (Quantity x u) y = reduceUnits $ Quantity (x**y) newUnits-  where expUnits = map (\(SimpleUnit s pr p) -> SimpleUnit s pr (p*y))+  where expUnits = map (\(SimpleUnit s pr p) -> SimpleUnit s pr (p * realToFrac y))         newUnits = u { sUnits = expUnits (sUnits u) }  -- | Data type for the three definition types. Used to hold definitions@@ -192,7 +191,7 @@                                    , dimBase     :: Symbol                                    , defSynonyms ::[Symbol]}                 | UnitDefinition   { defSymbol   :: Symbol-                                   , quantity    :: Quantity+                                   , quantity    :: Quantity Double                                    , defSynonyms :: [Symbol]} deriving (Show, Eq, Ord)  -- | Holds information about defined units, prefixes, and bases. Used when
library/Data/Quantities/DefaultUnits.hs view
@@ -13,9 +13,9 @@ -- second = min@. -- -- The reason these definitions aren't placed in a text file is so you don't--- have to operate your whole program in the IO monad. Theoretically, a user of--- this package can create their own definitions file or modify this one, but a--- mechanism for doing so hasn't been created yet.+-- have to operate your whole program in the IO monad. Users can copy this file+-- into their source and modify definitions, or simply add a few definitions to+-- the end of this string. -- -- These definitions are taken almost verbatim from the Pint unit conversion -- library for the Python programming language. Check them out on
library/Data/Quantities/Definitions.hs view
@@ -15,17 +15,17 @@  -- | Convert string of definitions into 'Definitions' structure. See source -- code for 'Data.Quantities.defaultDefString' for an example.-readDefinitions :: String -> Either QuantityError Definitions+readDefinitions :: String -> Either (QuantityError Double) Definitions readDefinitions s = addDefinitionsHash s <$> d   where d = makeDefinitions (parseDefinitions s)  -- | Monad used for addDefinition.-type DefineMonad = StateT Definitions (Either QuantityError)+type DefineMonad = StateT Definitions (Either (QuantityError Double))  -- | Converts a list of definitions to the Definitions data structure. Modifies -- an emptyDefinitions object by combining the incremental additions of each -- Definition.-makeDefinitions :: [Definition] -> Either QuantityError Definitions+makeDefinitions :: [Definition] -> Either (QuantityError Double) Definitions makeDefinitions ds = execStateT (mapM addDefinition ds) emptyDefinitions  -- | Add one definition to the definitions. Creates a new Definitions object
library/Data/Quantities/ExprParser.hs view
@@ -18,13 +18,14 @@ spaces' = many $ char ' '  -- | Parse quantity expression; addition and subtraction allowed.-parseExprQuant :: Definitions -> String -> Either QuantityError Quantity+parseExprQuant :: Definitions -> String ->+                  Either (QuantityError Double) (Quantity Double) parseExprQuant d input = case parse (parseExpr d) "arithmetic" input of   Left err  -> Left $ ParserError $ show err   Right val -> val  -- | Simple type used for shorthand-type EQuant = Either QuantityError Quantity+type EQuant = Either (QuantityError Double) (Quantity Double)  -- | Using already compiled definitions, parse expression. Also allows for -- expressions like "exp1 => exp2" in the middle, which converts the quantity@@ -70,7 +71,8 @@         parseSubtract = char '-' >> spaces' >> return subtractEQuants mulOp = try parseTimes <|> try parseDiv <|> parseImplicitTimes <?> "mulOp"   where parseTimes         = char '*' >> spaces' >> return multiplyEQuants-        parseDiv           = char '/' >> spaces' >> return divideEQuants+        parseDiv           = divOp >> spaces' >> return divideEQuants+          where divOp = try (string "/") <|> string "per "         parseImplicitTimes = return multiplyEQuants exptOp = try (opChoice >> spaces' >> return exptEQuants) <?> "expOp"   where opChoice = string "^" <|> string "**"@@ -125,7 +127,7 @@   return $ Right $ q { units = (units q) { defs = d } }  -- | Parses out prefixes and aliases from quantity's units.-preprocessQuantity :: Definitions -> Quantity -> Either QuantityError Quantity+preprocessQuantity :: Definitions -> Quantity Double -> EQuant preprocessQuantity d (Quantity x us)   | null errs = Right $ Quantity x (CompoundUnit d us')   | otherwise = Left  $ head errs@@ -133,7 +135,7 @@           (errs, us') = partitionEithers ppUnits  -- | Parses prefix and alias, if applicable, from a SimpleUnit.-preprocessUnit :: Definitions -> SimpleUnit -> Either QuantityError SimpleUnit+preprocessUnit :: Definitions -> SimpleUnit -> Either (QuantityError Double) SimpleUnit preprocessUnit d (SimpleUnit s _ p)   | rs `elem` unitsList d = Right $ SimpleUnit ns np p   | otherwise             = Left  $ UndefinedUnitError s@@ -159,10 +161,10 @@ -- | Converts string to a Quantity using an expression grammar parser. This -- parser does not parser addition or subtraction, and is used for unit -- definitions.-parseMultExpr :: Parser Quantity+parseMultExpr :: Parser (Quantity Double) parseMultExpr = spaces' >> parseMultExpr' <* spaces' -parseMultExpr', parseMultFactor, parseMultExpt, parseMultNestedExpr :: Parser Quantity+parseMultExpr', parseMultFactor, parseMultExpt, parseMultNestedExpr :: Parser (Quantity Double) parseMultExpr'      = try parseMultFactorOp   <|> parseMultFactor parseMultFactor     = try parseMultExptOp     <|> parseMultExpt parseMultExpt       = try parseMultNestedExpr <|> parseSymbolNum@@ -171,11 +173,11 @@                       <* spaces' <* char ')' <* spaces' <?> "parseNested"  -parseMultExptOp, parseMultFactorOp :: Parser Quantity+parseMultExptOp, parseMultFactorOp :: Parser (Quantity Double) parseMultExptOp     = parseMultExpt   `chainl1` exptMultOp parseMultFactorOp   = parseMultFactor `chainl1` mulMultOp -exptMultOp, mulMultOp :: Parser (Quantity -> Quantity -> Quantity)+exptMultOp, mulMultOp :: Parser (Quantity Double -> Quantity Double -> Quantity Double) mulMultOp = try parseTimes <|> try parseDiv <|> parseImplicitTimes <?> "mulMultOp"   where parseTimes         = char '*' >> spaces' >> return multiplyQuants         parseDiv           = char '/' >> spaces' >> return divideQuants@@ -183,18 +185,18 @@ exptMultOp = try (opChoice >> spaces' >> return exptMultQuants') <?> "expMultOp"   where opChoice = string "^" <|> string "**" -exptMultQuants' :: Quantity -> Quantity -> Quantity+exptMultQuants' :: (Quantity Double -> Quantity Double -> Quantity Double) exptMultQuants' q (Quantity y (CompoundUnit _ [])) = exptQuants q y exptMultQuants' a b  = error $ "Used non-dimensionless exponent in " ++ showq   where showq = unwords ["(", show a, ") ** (", show b, ")"]  -- | Parse either a symbol or a number.-parseSymbolNum :: Parser Quantity+parseSymbolNum :: Parser (Quantity Double) parseSymbolNum = try parseNum <|> parseSymbol'  -- | Parse a symbol with an optional negative sign. A symbol can contain -- alphanumeric characters and the character '_'.-parseSymbol' :: Parser Quantity+parseSymbol' :: Parser (Quantity Double) parseSymbol' = do   neg  <- option "" $ string "-"   symf <- letter@@ -203,7 +205,7 @@   return $ baseQuant (timesSign neg 1) [SimpleUnit (symf : rest) "" 1]  -- | Parent function for parseNum' to parse a number.-parseNum :: Parser Quantity+parseNum :: Parser (Quantity Double) parseNum = do   num <- parseNum'   return $ baseQuant num []
quantities.cabal view
@@ -1,10 +1,10 @@ name:                 quantities-version:              0.3.0-author:               John David Reaver <jdreaver@adlerhorst.com>-maintainer:           John David Reaver <jdreaver@adlerhorst.com>+version:              0.4.0+author:               John David Reaver <johndreaver@gmail.com>+maintainer:           John David Reaver <johndreaver@gmail.com> build-type:           Simple cabal-version:        >= 1.18-copyright:            2014 John David Reaver+copyright:            Copyright (c) 2014-2015 John David Reaver license:              BSD3 license-file:         LICENSE synopsis:             Unit conversion and manipulation library.@@ -18,7 +18,7 @@                       or queried for its dimensionality. A user can                       also operate on quantities arithmetically, and                       doing so uses automatic unit conversion and-                      simplifcation.+                      simplification.  category:             Data, Math, Physics homepage:             http://github.com/jdreaver/quantities@@ -39,6 +39,13 @@                     , Data.Quantities.DefinitionParser                     , Data.Quantities.ExprParser +executable quantities+    default-language: Haskell2010+    Hs-Source-Dirs:   .+    Main-Is:          quantities.hs+    build-depends:    base >=4 && < 5, quantities, containers, mtl, parsec+    Buildable:        True+ test-suite hspec     default-language: Haskell2010     ghc-options:      -Wall@@ -55,14 +62,14 @@     type:             exitcode-stdio-1.0  test-suite doctest-    build-depends:    base, doctest == 0.9.*, Glob == 0.7.*+    build-depends:    base, doctest, Glob     default-language: Haskell2010     hs-source-dirs:   test-suite     main-is:          DocTest.hs     type:             exitcode-stdio-1.0  test-suite coverage-    build-depends:    base, process == 1.1.*, regex-compat == 0.95.*+    build-depends:    base, process, regex-compat     default-language: Haskell2010     hs-source-dirs:   test-suite     main-is:          DocCoverage.hs
+ quantities.hs view
@@ -0,0 +1,19 @@+import System.Environment+import System.Exit++import Data.Quantities++main :: IO ()+main = getArgs >>= parse++parse :: [String] -> IO ()+parse ["-h"] = usage   >> exit+parse ["-v"] = version >> exit+parse []     = usage   >> exit+parse [s]    = putStr $ (++ "\n") $ either show show $ fromString s+parse _      = usage   >> Main.die++usage   = putStrLn "Usage: quantities [-vh] expression"+version = putStrLn "Haskell quantities 0.3.0"+exit    = exitSuccess+die     = exitWith (ExitFailure 1)