packages feed

mathexpr 0.2.0.1 → 0.3.0.0

raw patch · 3 files changed

+116/−116 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.MathExpr: Settings :: [(Char, Int, Double -> Double -> Double)] -> [(String, Double -> Double)] -> Settings
- Data.MathExpr: [functions] :: Settings -> [(String, Double -> Double)]
- Data.MathExpr: [operators] :: Settings -> [(Char, Int, Double -> Double -> Double)]
- Data.MathExpr: data Settings
- Data.MathExpr: defaultFunctions :: [([Char], Double -> Double)]
- Data.MathExpr: defaultOperators :: [(Char, Int, Double -> Double -> Double)]
- Data.MathExpr: evaluate :: Settings -> String -> [(String, Double)] -> Double
- Data.MathExpr: instance Data.Default.Class.Default Data.MathExpr.Settings
+ Numeric.MathExpr: Settings :: [(Char, Int, Double -> Double -> Double)] -> [(String, Double -> Double)] -> Settings
+ Numeric.MathExpr: [functions] :: Settings -> [(String, Double -> Double)]
+ Numeric.MathExpr: [operators] :: Settings -> [(Char, Int, Double -> Double -> Double)]
+ Numeric.MathExpr: data Settings
+ Numeric.MathExpr: defaultFunctions :: [([Char], Double -> Double)]
+ Numeric.MathExpr: defaultOperators :: [(Char, Int, Double -> Double -> Double)]
+ Numeric.MathExpr: evaluate :: Settings -> String -> [(String, Double)] -> Double
+ Numeric.MathExpr: instance Data.Default.Class.Default Numeric.MathExpr.Settings

Files

mathexpr.cabal view
@@ -1,5 +1,5 @@ name:                mathexpr-version:             0.2.0.1+version:             0.3.0.0 synopsis:            Parse and evaluate math expressions with variables and functions description:         A simple tool to evaluate math expressions as strings with support for custom functions and operators homepage:            https://github.com/mdibaiee/mathexpr@@ -15,7 +15,7 @@  library   hs-source-dirs:      src-  exposed-modules:     Data.MathExpr+  exposed-modules:     Numeric.MathExpr   build-depends:       base >= 4.7 && < 5,                        data-default-class   default-language:    Haskell2010
− src/Data/MathExpr.hs
@@ -1,114 +0,0 @@-{-# Language ScopedTypeVariables #-}-module Data.MathExpr-    ( evaluate-    , Settings (..)-    , defaultFunctions-    , defaultOperators-    ) where-      import Data.Default.Class-      import Data.Maybe (isJust, fromJust)-      import Data.List (find)--      data Settings = Settings { operators :: [(Char, Int, Double -> Double -> Double)]-                               , functions :: [(String, Double -> Double)]-                               }--      defaultOperators = [-          ('+', 0, (+)), ('-', 0, (-)),-          ('*', 1, (*)), ('/', 1, (/)),-          ('^', 2, (**))-        ]-      defaultFunctions = [("ln", log), ("sin", sin), ("cos", cos)]--      instance Default Settings where-        def = Settings { operators = defaultOperators-                       , functions = defaultFunctions-                       }-      toPostfix :: Settings -> String -> String-      toPostfix settings s = helper (tokenize s) [] []-        where-          ops = operators settings-          fns = functions settings--          helper :: [String] -> [String] -> String -> String-          helper [] os out = out ++ concat os-          helper (c:cs) os out-            | head c == '(' = helper cs (c:os) out-            | head c == ')' && head os == "(" = helper cs (tail os) out-            | head c == ')' = helper (c:cs) (tail os) (out ++ pad (head os))-            | isOperator c && (null os || precedence c > precedence (head os)) = helper cs (c:os) out-            | isOperator c = helper (c:cs) (tail os) (out ++ pad (head os))-            | otherwise = helper cs os (out ++ pad c)--          isOperator cs = isOp cs || isFunction cs-          isOp cs = isJust $ (head cs) `triLookup` ops-          isFunction cs = isJust $ cs `lookup` fns-          precedence cs-            | isFunction cs = Just 999-            | otherwise = (head cs) `triLookup` ops--      tokenize :: String -> [String]-      tokenize str = words $ helper str-        where-          helper :: String -> String-          helper [] = []-          helper (c:cs)-            | isAlphanumeric c = c : helper cs-            | isSymbol c = pad [c] ++ helper cs--      replaceVariables :: String -> [(String, Double)] -> String-      replaceVariables str [] = str-      replaceVariables str vars = concatMap replace (tokenize str)-        where-          replace c-            | isVariable c = pad $ show $ fromJust $ c `lookup` vars-            | otherwise = c--          isVariable c = isJust $ c `lookup` vars--      -- | Evaluate an expression-      -- Example: `evaluate def "x + y ^ 2" [("x", 1), ("y", 2)]-      evaluate :: Settings -> String -> [(String, Double)] -> Double-      evaluate settings expr vars =-        let postfix = toPostfix settings expr-            replaced = replaceVariables postfix vars-        in helper (tokenize replaced) []-        where-          ops = operators settings-          fns = functions settings--          helper :: [String] -> [String] -> Double-          -- negative numbers come in the form ["num", "-"]-          helper [] [o] = read o-          helper [n, "-"] [] = negate . read $ n-          helper ["-"] [n] = negate . read $ n-          helper (c:cs) os-            | c == "-" && length os < 2 =-                let result :: Double = negate . read . head $ cs-                in helper (tail cs) $ (show result) : os-            | isOperator c && length os >= 2 =-                let result = (operatorFunction c) (read . head . tail $ os) (read . head $ os) -                in helper cs $ (show result) : drop 2 os-            | isFunction c =-                let result = (function c) (read . head $ os)-                in helper cs $ (show result) : tail os-            | otherwise = helper cs (c:os)--          isOperator cs = isJust $ (head cs) `triLookup` ops-          isFunction cs = isJust $ cs `lookup` fns--          function cs = fromJust $ cs `lookup` fns-          operatorFunction cs = case find (\(a, _, _) -> a == head cs) ops of-                                  Just (_, _, c) -> c-                                  Nothing -> const (const 0)-          isParen cs = head cs `elem` ['(', ')']--      alphanumeric = '.' : ['a'..'z'] ++ ['0'..'9']-      isAlphanumeric = (`elem` alphanumeric)-      isSymbol = not . (`elem` alphanumeric)  --      triLookup :: (Eq a) => a -> [(a, b, c)] -> Maybe b-      triLookup a x = lookup a $ map (\(a, b, _) -> (a, b)) x--      pad :: String -> String-      pad x = ' ' : x ++ [' ']
+ src/Numeric/MathExpr.hs view
@@ -0,0 +1,114 @@+{-# Language ScopedTypeVariables #-}+module Numeric.MathExpr+    ( evaluate+    , Settings (..)+    , defaultFunctions+    , defaultOperators+    ) where+      import Data.Default.Class+      import Data.Maybe (isJust, fromJust)+      import Data.List (find)++      data Settings = Settings { operators :: [(Char, Int, Double -> Double -> Double)]+                               , functions :: [(String, Double -> Double)]+                               }++      defaultOperators = [+          ('+', 0, (+)), ('-', 0, (-)),+          ('*', 1, (*)), ('/', 1, (/)),+          ('^', 2, (**))+        ]+      defaultFunctions = [("ln", log), ("sin", sin), ("cos", cos)]++      instance Default Settings where+        def = Settings { operators = defaultOperators+                       , functions = defaultFunctions+                       }+      toPostfix :: Settings -> String -> String+      toPostfix settings s = helper (tokenize s) [] []+        where+          ops = operators settings+          fns = functions settings++          helper :: [String] -> [String] -> String -> String+          helper [] os out = out ++ concat os+          helper (c:cs) os out+            | head c == '(' = helper cs (c:os) out+            | head c == ')' && head os == "(" = helper cs (tail os) out+            | head c == ')' = helper (c:cs) (tail os) (out ++ pad (head os))+            | isOperator c && (null os || precedence c > precedence (head os)) = helper cs (c:os) out+            | isOperator c = helper (c:cs) (tail os) (out ++ pad (head os))+            | otherwise = helper cs os (out ++ pad c)++          isOperator cs = isOp cs || isFunction cs+          isOp cs = isJust $ (head cs) `triLookup` ops+          isFunction cs = isJust $ cs `lookup` fns+          precedence cs+            | isFunction cs = Just 999+            | otherwise = (head cs) `triLookup` ops++      tokenize :: String -> [String]+      tokenize str = words $ helper str+        where+          helper :: String -> String+          helper [] = []+          helper (c:cs)+            | isAlphanumeric c = c : helper cs+            | isSymbol c = pad [c] ++ helper cs++      replaceVariables :: String -> [(String, Double)] -> String+      replaceVariables str [] = str+      replaceVariables str vars = concatMap replace (tokenize str)+        where+          replace c+            | isVariable c = pad $ show $ fromJust $ c `lookup` vars+            | otherwise = c++          isVariable c = isJust $ c `lookup` vars++      -- | Evaluate an expression+      -- Example: `evaluate def "x + y ^ 2" [("x", 1), ("y", 2)]+      evaluate :: Settings -> String -> [(String, Double)] -> Double+      evaluate settings expr vars =+        let postfix = toPostfix settings expr+            replaced = replaceVariables postfix vars+        in helper (tokenize replaced) []+        where+          ops = operators settings+          fns = functions settings++          helper :: [String] -> [String] -> Double+          -- negative numbers come in the form ["num", "-"]+          helper [] [o] = read o+          helper [n, "-"] [] = negate . read $ n+          helper ["-"] [n] = negate . read $ n+          helper (c:cs) os+            | c == "-" && length os < 2 =+                let result :: Double = negate . read . head $ cs+                in helper (tail cs) $ (show result) : os+            | isOperator c && length os >= 2 =+                let result = (operatorFunction c) (read . head . tail $ os) (read . head $ os) +                in helper cs $ (show result) : drop 2 os+            | isFunction c =+                let result = (function c) (read . head $ os)+                in helper cs $ (show result) : tail os+            | otherwise = helper cs (c:os)++          isOperator cs = isJust $ (head cs) `triLookup` ops+          isFunction cs = isJust $ cs `lookup` fns++          function cs = fromJust $ cs `lookup` fns+          operatorFunction cs = case find (\(a, _, _) -> a == head cs) ops of+                                  Just (_, _, c) -> c+                                  Nothing -> const (const 0)+          isParen cs = head cs `elem` ['(', ')']++      alphanumeric = '.' : ['a'..'z'] ++ ['0'..'9']+      isAlphanumeric = (`elem` alphanumeric)+      isSymbol = not . (`elem` alphanumeric)  ++      triLookup :: (Eq a) => a -> [(a, b, c)] -> Maybe b+      triLookup a x = lookup a $ map (\(a, b, _) -> (a, b)) x++      pad :: String -> String+      pad x = ' ' : x ++ [' ']