diff options
| author | Raymond Hogenson <rhogenson@posteo.net> | 2018-05-17 09:42:44 -0800 |
|---|---|---|
| committer | Raymond Hogenson <rhogenson@posteo.net> | 2018-05-17 09:43:54 -0800 |
| commit | 78001436a52a4cc9b5e22bca489fb8ed09a72376 (patch) | |
| tree | 0c88a126b1169000d6312d21792b10e8724fab6f /Expr.hs | |
| download | hsc-78001436a52a4cc9b5e22bca489fb8ed09a72376.tar.zst | |
Write a calculator
It's pretty nice. It works for what I want. I don't think I have any
complaints about its functionality. I'll add new functions as I need
them. Haskell is actually really easy to program in. I wonder actually
if this would have been easier in Python. I think no.
Diffstat (limited to 'Expr.hs')
| -rw-r--r-- | Expr.hs | 66 |
1 files changed, 66 insertions, 0 deletions
@@ -0,0 +1,66 @@ +module Expr (parseE, Expr(..)) where + +import Text.Parsec +import Text.Parsec.Language +import Text.Parsec.Token +import Text.Parsec.Expr +import qualified Data.Functor.Identity + +data Expr = Plus Expr Expr + | Negate Expr + | Minus Expr Expr + | Times Expr Expr + | Div Expr Expr + | EInt Integer + | EFloat Double + | E + | Pi + | Log Expr + | Sin Expr + | Cos Expr + | Sqrt Expr + +tokenParser :: TokenParser st +tokenParser = haskell + +parseNumber :: Parsec String u Expr +parseNumber = do n <- naturalOrFloat tokenParser + case n of + Left i -> return (EInt i) + Right d -> return (EFloat d) + +tokenS :: String -> Parsec String u () +tokenS s = () <$ try (symbol tokenParser s) + +inner :: Parsec String u Expr +inner = parseNumber <|> E <$ tokenS "e" <|> Pi <$ tokenS "pi" <|> parens tokenParser parseExpr + +binary :: String -> (a -> a -> a) -> Assoc + -> Operator String u Data.Functor.Identity.Identity a +binary name fun assoc = + Infix (fun <$ tokenS name) assoc + +prefix :: String -> (a -> a) + -> Operator String u Data.Functor.Identity.Identity a +prefix name fun = Prefix (fun <$ tokenS name) + +table :: [[Operator String u Data.Functor.Identity.Identity Expr]] +table = [ [ prefix "log" Log, prefix "sin" Sin, prefix "cos" Cos, prefix "sqrt" Sqrt ] + , [ prefix "-" Negate ] + , [ binary "*" Times AssocLeft + , binary "/" Div AssocLeft + ] + , [ binary "+" Plus AssocLeft + , binary "-" Minus AssocLeft + ] + ] + +parseExpr :: Parsec String u Expr +parseExpr = buildExpressionParser table inner + +parser :: Parsec String u Expr +parser = do whiteSpace tokenParser + parseExpr + +parseE :: String -> Either ParseError Expr +parseE s = parse parser "" s |
