41 lines
1.1 KiB
Haskell
41 lines
1.1 KiB
Haskell
-- calculator.hs — recursive descent expression evaluator.
|
|
--
|
|
-- Tokens are represented as an ADT; the parser threads a [Token] list
|
|
-- through a custom Result type so pattern matching can destructure the
|
|
-- pair (value, remaining-tokens) directly inside constructor patterns.
|
|
--
|
|
-- Operator precedence: * and / bind tighter than + and -.
|
|
-- All operators are left-associative.
|
|
|
|
data Token = TNum Int | TOp String
|
|
data Result = R Int [Token]
|
|
|
|
getV (R v _) = v
|
|
getR (R _ r) = r
|
|
|
|
eval ts = getV (parseExpr ts)
|
|
|
|
parseExpr ts = parseExprRest (parseTerm ts)
|
|
|
|
parseExprRest (R v (TOp "+":rest)) =
|
|
let t = parseTerm rest
|
|
in parseExprRest (R (v + getV t) (getR t))
|
|
parseExprRest (R v (TOp "-":rest)) =
|
|
let t = parseTerm rest
|
|
in parseExprRest (R (v - getV t) (getR t))
|
|
parseExprRest r = r
|
|
|
|
parseTerm ts = parseTermRest (parseFactor ts)
|
|
|
|
parseTermRest (R v (TOp "*":rest)) =
|
|
let t = parseFactor rest
|
|
in parseTermRest (R (v * getV t) (getR t))
|
|
parseTermRest (R v (TOp "/":rest)) =
|
|
let t = parseFactor rest
|
|
in parseTermRest (R (v `div` getV t) (getR t))
|
|
parseTermRest r = r
|
|
|
|
parseFactor (TNum n:rest) = R n rest
|
|
|
|
result = eval [TNum 2, TOp "+", TNum 3, TOp "*", TNum 4]
|