Skip to content

Instantly share code, notes, and snippets.

@hughfdjackson
Last active August 29, 2015 14:07
Show Gist options
  • Save hughfdjackson/5a54eefd59400c3dff50 to your computer and use it in GitHub Desktop.
Save hughfdjackson/5a54eefd59400c3dff50 to your computer and use it in GitHub Desktop.
import Text.Parsec
import Text.Parsec.String
import Control.Applicative hiding (many, (<|>))
data Calc = Number Float
| OpPlus Calc Calc
| OpMult Calc Calc
| OpSubt Calc Calc
| OpDivd Calc Calc
instance Show Calc where
show (Number a) = show a
show (OpPlus c c') = "(" ++ show c ++ " + " ++ show c' ++ ")"
show (OpSubt c c') = "(" ++ show c ++ " - " ++ show c' ++ ")"
show (OpMult c c') = "(" ++ show c ++ " * " ++ show c' ++ ")"
show (OpDivd c c') = "(" ++ show c ++ " / " ++ show c' ++ ")"
-- INTERPRETING
intr :: String -> Either ParseError Float
intr str = eval <$> parse calc "(unknown)" str
-- EVALUATING
eval :: Calc -> Float
eval (Number a) = a
eval (OpPlus c c') = (eval c) + (eval c')
eval (OpSubt c c') = (eval c) - (eval c')
eval (OpMult c c') = (eval c) * (eval c')
eval (OpDivd c c') = (eval c) / (eval c') -- divide by zero doesn't error - that's 'inifinity'
-- PARSING
-- <expression> ::= <term> <plussubt> | <term>
-- <plussubt> ::= + <expression> | - <expression>
-- <term> ::= <factor> <multdivd> | <factor>
-- <multdivd> ::= * <factor> | / <factor>
-- <factor> ::= "(" <expression> ")" | number
-- Parsers
calc = expression
expression = term `chainl1` plusSubt <||> term
term = factor `chainl1` multDivd <||> factor
factor = parens expression <||> number
multDivd = withSpaces mult <||> withSpaces divd
plusSubt = withSpaces plus <||> withSpaces subt
-- minimal parsers
mult = char '*' >> return OpMult
plus = char '+' >> return OpPlus
subt = char '-' >> return OpSubt
divd = char '/' >> return OpDivd
number = Number <$> (read <$> many1 digit)
-- helpers
(<||>) :: Parser a -> Parser a -> Parser a
a <||> b = try a <|> try b
parens :: Parser a -> Parser a
parens = between (char '(') (char ')')
withSpaces :: Parser a -> Parser a
withSpaces = between spaces spaces
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment