Skip to content

Commit c038ddb

Browse files
Normalize will now filter multipliers from every dimension
1 parent 532f4d3 commit c038ddb

File tree

5 files changed

+13
-15
lines changed

5 files changed

+13
-15
lines changed

src/Math/Haskellator/Internal/AstProcessingSteps/Evaluate.hs

+3-9
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ execute :: Expr -- ^ the expression tree to evaluate
2828
-> Either Error (Value Dimension) -- ^ the result or an error
2929
execute expr = do
3030
r <- runAstFold $ execute' expr
31-
return $ r { unit = filterUnwanted $ unit r }
31+
return $ r { unit = filterZeroPower $ unit r }
3232

3333
execute' :: Expr -> SimpleAstFold (Value Dimension)
3434
execute' = partiallyFoldExprM execVal execBinOp execUnaryOp execConversion execVarBinds execVar
@@ -48,10 +48,10 @@ execBinOp lhs Div rhs = do
4848
let u = subtractUnits (unit lhs) (unit rhs)
4949
return $ Value (value lhs / value rhs) u
5050
execBinOp lhs Pow rhs = case rhs of
51-
Value _ [UnitExp Multiplier _] -> return $ Value (value lhs ** value rhs) ((\u -> u {
51+
Value _ [] -> return $ Value (value lhs ** value rhs) ((\u -> u {
5252
power = power u * (round (value rhs) :: Int)
5353
}) <$> unit lhs)
54-
_ -> throwError $ Error RuntimeError "Exponentiation of units is not supported"
54+
_ -> throwError $ Error RuntimeError "Exponentiation of units is not supported"
5555
execBinOp _ op _ = throwError $ Error ImplementationError $ "Unknown binary operator " ++ show op
5656

5757
execUnaryOp :: Op -> Value Dimension -> SimpleAstFold (Value Dimension)
@@ -105,11 +105,5 @@ findPair x (y:ys) | dimUnit x == dimUnit y = ([(x, y)], ([], ys))
105105
| otherwise = let (pair, (lr, rr)) = findPair x ys
106106
in (pair, (lr, y:rr))
107107

108-
filterUnwanted :: Dimension -> Dimension
109-
filterUnwanted = filterZeroPower . filterMultiplier
110-
111108
filterZeroPower :: Dimension -> Dimension
112109
filterZeroPower = filter ((/=0) . power)
113-
114-
filterMultiplier :: Dimension -> Dimension
115-
filterMultiplier = filter (not . isMultiplier . dimUnit)

src/Math/Haskellator/Internal/AstProcessingSteps/Normalize.hs

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import Math.Haskellator.Internal.Utils.Error
1717
-- | Normalize all values inside the tree to their base units
1818
normalize :: Expr -- ^ the 'Expr' tree to normalize
1919
-> Either Error Expr -- ^ the normalized 'Expr' tree
20-
normalize = Right . foldExpr (Val . convertDimensionToBase) BinOp UnaryOp Conversion VarBindings Var
20+
normalize = Right . foldExpr (Val . filterMultiplier . convertDimensionToBase) BinOp UnaryOp Conversion VarBindings Var
2121

2222
-- | Converts a value to its base dimension
2323
-- >>> convertDimensionToBase $ Value 1 [UnitExp Kilometer 2, UnitExp Hour 1]
@@ -59,3 +59,6 @@ convertUnit s (t:ts) val@(Value v u) = case convertTo (Value 1 s) t of
5959
Nothing -> do
6060
(v', rest) <- convertUnit s ts val
6161
return (v', t:rest)
62+
63+
filterMultiplier :: AstValue -> AstValue
64+
filterMultiplier (Value v u) = Value v $ filter (not . isMultiplier . dimUnit) u

src/Math/Haskellator/Internal/Parser.hs

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import Control.Monad.State
3535
import Data.Bifunctor
3636

3737
import Math.Haskellator.Internal.AstProcessingSteps.Evaluate
38+
import Math.Haskellator.Internal.AstProcessingSteps.Normalize
3839
import Math.Haskellator.Internal.DerivedUnits
3940
import Math.Haskellator.Internal.Expr
4041
import Math.Haskellator.Internal.Lexer
@@ -164,7 +165,7 @@ parseUnitExp = do
164165
either (\x -> fail $ "Invalid unit " ++ x) (\dim -> do {
165166
requireOperator "^";
166167
expr <- parsePrimary;
167-
case execute expr of
168+
case normalize expr >>= execute of
168169
Right (Value v []) -> let e = round v :: Int in return ((\(UnitExp u e') -> UnitExp u $ e' * e) <$> dim)
169170
_ -> fail "Exponentiation of units is not supported"
170171
} <|> return dim) $ parseUnitSymbol i

test/Evaluation.hs

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ normalization = testGroup "Normalization" [
4040
@?= Right (BinOp (Val $ Value 1 $ meter 42) Div (Val $ Value 1 $ second 33))
4141
]
4242

43-
evalString :: String -> Either Error Double
44-
evalString = scan >=> parse >=> evaluate
45-
4643
normalizeString :: String -> Either Error Expr
4744
normalizeString = scan >=> parse >=> normalize
45+
46+
evalString :: String -> Either Error Double
47+
evalString = normalizeString >=> evaluate

test/Parser.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ genInt = do
6565
instance Arbitrary Unit where
6666
-- Multiplier needs to be excluded here to prevent ambiguous cases in our grammar
6767
-- e.g. 2^2 could be either a multiplier with exponent two or a power operation on two multipliers with exponent 1
68-
arbitrary = arbitraryBoundedEnum `suchThat` (/= Multiplier)
68+
arbitrary = arbitraryBoundedEnum `suchThat` (not . isMultiplier)
6969

7070
instance Arbitrary Expr where
7171
arbitrary = let randomValue = do {

0 commit comments

Comments
 (0)