|
9 | 9 | {-# LANGUAGE FlexibleInstances #-}
|
10 | 10 | {-# LANGUAGE GADTs #-}
|
11 | 11 | {-# LANGUAGE KindSignatures #-}
|
| 12 | +{-# LANGUAGE LambdaCase #-} |
12 | 13 | {-# LANGUAGE RankNTypes #-}
|
13 | 14 | {-# LANGUAGE ScopedTypeVariables #-}
|
14 | 15 | {-# LANGUAGE StandaloneDeriving #-}
|
@@ -172,15 +173,14 @@ asSimple n | isSimple n = weaken n
|
172 | 173 | | otherwise = grouped n
|
173 | 174 |
|
174 | 175 | evaluate :: (Group a) => UnitName' m a -> a
|
175 |
| -evaluate One = mempty |
176 |
| -evaluate (MetricAtomic a) = a |
177 |
| -evaluate (Atomic a) = a |
178 |
| -evaluate (Prefixed p a) = p `mappend` a |
179 |
| -evaluate (Product n1 n2) = evaluate n1 `mappend` evaluate n2 |
180 |
| -evaluate (Quotient n1 n2) = evaluate n1 `mappend` (invert $ evaluate n2) |
181 |
| -evaluate (Power n x) = pow (evaluate n) x |
182 |
| -evaluate (Grouped n) = evaluate n |
183 |
| -evaluate (Weaken n) = evaluate n |
| 176 | +evaluate = foldName $ UnitNameFold { |
| 177 | + foldOne = mempty |
| 178 | + , foldPrefix = mappend |
| 179 | + , foldProduct = mappend |
| 180 | + , foldQuotient = \n1 n2 -> n1 `mappend` (invert n2) |
| 181 | + , foldPower = pow |
| 182 | + , foldGrouped = id |
| 183 | + } |
184 | 184 |
|
185 | 185 | evaluateMolecules :: (Group b) => (NameMolecule a -> b) -> UnitName' m a -> b
|
186 | 186 | evaluateMolecules _ One = mempty
|
@@ -229,13 +229,34 @@ eliminateRedundantPowers :: UnitName' m a -> UnitName' m a
|
229 | 229 | eliminateRedundantPowers (Product n1 n2) = Product (eliminateRedundantPowers n1) (eliminateRedundantPowers n2)
|
230 | 230 | eliminateRedundantPowers (Quotient n1 n2) = Quotient (eliminateRedundantPowers n1) (eliminateRedundantPowers n2)
|
231 | 231 | eliminateRedundantPowers (Power One _) = One
|
| 232 | +eliminateRedundantPowers (Power (Power n x1) x2) = eliminateRedundantPowers (Power n (x1 P.* x2)) |
232 | 233 | eliminateRedundantPowers n@(Power n' x) | x == 0 = One
|
233 | 234 | | x == 1 = eliminateRedundantPowers n'
|
234 | 235 | | otherwise = n
|
235 | 236 | eliminateRedundantPowers (Grouped n) = Grouped (eliminateRedundantPowers n)
|
236 | 237 | eliminateRedundantPowers (Weaken n) = Weaken (eliminateRedundantPowers n)
|
237 | 238 | eliminateRedundantPowers n = n
|
238 | 239 |
|
| 240 | +distributePowers :: UnitName' m a -> UnitName' m a |
| 241 | +distributePowers = \case |
| 242 | + (Product n1 n2) -> Product (distributePowers n1) (distributePowers n2) |
| 243 | + (Quotient n1 n2) -> Quotient (distributePowers n1) (distributePowers n2) |
| 244 | + n@(Power _ _) -> go 1 n |
| 245 | + (Grouped n) -> Grouped (distributePowers n) |
| 246 | + (Weaken n) -> Weaken (distributePowers n) |
| 247 | + One -> One |
| 248 | + n@(Atomic _) -> n |
| 249 | + n@(MetricAtomic _) -> n |
| 250 | + n@(Prefixed _ _) -> n |
| 251 | + where |
| 252 | + go :: Int -> UnitName' m a -> UnitName' 'NonMetric a |
| 253 | + go x (Product n1 n2) = Product (go x n1) (go x n2) |
| 254 | + go x (Quotient n1 n2) = Quotient (go x n1) (go x n2) |
| 255 | + go x (Power n x') = go (x P.* x') n |
| 256 | + go x (Grouped n) = Grouped (go x n) |
| 257 | + go x (Weaken n) = weaken (go x n) |
| 258 | + go x n = Power (weaken n) x |
| 259 | + |
239 | 260 | ensureSimpleDenominatorsAndPowers :: UnitName' m a -> UnitName' m a
|
240 | 261 | ensureSimpleDenominatorsAndPowers (Product n1 n2) = Product (ensureSimpleDenominatorsAndPowers n1) (ensureSimpleDenominatorsAndPowers n2)
|
241 | 262 | ensureSimpleDenominatorsAndPowers (Quotient n1 n2) = Quotient (ensureSimpleDenominatorsAndPowers n1) (asSimple $ ensureSimpleDenominatorsAndPowers n2)
|
@@ -476,31 +497,26 @@ grouped :: UnitName' m a -> UnitName' 'NonMetric a
|
476 | 497 | grouped = Grouped . weaken
|
477 | 498 |
|
478 | 499 | ucumName :: (HasUnitName a) => a -> Maybe String
|
479 |
| -ucumName = ucumName' . unitName |
| 500 | +ucumName = foldName f . fmap (nameComponent ucum) . ensureSimpleDenominatorsAndPowers . distributePowers . unitName |
480 | 501 | where
|
481 |
| - ucumName' :: UnitName m -> Maybe String |
482 |
| - ucumName' One = Just "1" |
483 |
| - ucumName' (MetricAtomic a) = nameComponent ucum a |
484 |
| - ucumName' (Atomic a) = nameComponent ucum a |
485 |
| - ucumName' (Prefixed p n) = (++) <$> nameComponent ucum p <*> nameComponent ucum n |
486 |
| - ucumName' (Product n1 n2) = do |
487 |
| - n1' <- ucumName' n1 |
488 |
| - n2' <- ucumName' n2 |
489 |
| - return $ n1' ++ "." ++ n2' |
490 |
| - -- TODO: does one of these subexpressions require a grouping if it is itself a quotient? seems like it must |
491 |
| - -- we did it at construction time, but if we are going to expose the constructors then we need to do it again. |
492 |
| - ucumName' (Quotient n1 n2) = do |
493 |
| - n1' <- ucumName' n1 |
494 |
| - n2' <- ucumName' n2 |
495 |
| - return $ n1' ++ "/" ++ n2' |
496 |
| - -- TODO #109: note in this case that the UCUM is changing their grammar to not accept exponents after |
497 |
| - -- as a result it will become necessary to distribute the exponentiation over the items in the base name |
498 |
| - -- prior to generating the UCUM name |
499 |
| - ucumName' (Power n x) = do |
500 |
| - n' <- ucumName' n |
501 |
| - return $ n' ++ show x |
502 |
| - ucumName' (Grouped n) = (\x -> "(" ++ x ++ ")") <$> ucumName' n |
503 |
| - ucumName' (Weaken n) = ucumName' n |
| 502 | + f = UnitNameFold { |
| 503 | + foldOne = Just "1" |
| 504 | + , foldPrefix = liftA2 (++) |
| 505 | + , foldProduct = \n1 n2 -> do |
| 506 | + n1' <- n1 |
| 507 | + n2' <- n2 |
| 508 | + return $ n1' ++ "." ++ n2' |
| 509 | + , foldQuotient = \n1 n2 -> do |
| 510 | + n1' <- n1 |
| 511 | + n2' <- n2 |
| 512 | + return $ n1' ++ "/" ++ n2' |
| 513 | + , foldPower = \n x -> do |
| 514 | + n' <- n |
| 515 | + return $ n' ++ show x |
| 516 | + , foldGrouped = \n -> do |
| 517 | + n' <- n |
| 518 | + return $ "(" ++ n' ++ ")" |
| 519 | + } |
504 | 520 |
|
505 | 521 | prefix :: String -> String -> String -> Int -> Prefix
|
506 | 522 | prefix i a f = Prefix n
|
|
0 commit comments