-- 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]