H. Conrad Cunningham
24 November 2018
Copyright (C) 2017, 2018, H. Conrad Cunningham
Acknowledgements: I originally created these slides in Fall 2017 to accompany what is now Chapter 42, Calculator: Abstract Syntax & Evaluation, in the 2018 version of the textbook Exploring Languages with Interpreters and Functional Programming.
Browser Advisory: The HTML version of this document may require use of a browser that supports the display of MathML. A good choice as of November 2018 is a recent version of Firefox from Mozilla.
Examine interpreter for simple ELI Calculator language
Concrete syntax: express language details in text strings (source code) — Ch. 41
Abstract syntax: express essential structure, ignore incidental representation issues (intermediate representation) — this chapter
Abstract Syntax module exports data type definition
Abstract Syntax module encapsulates instance definition
AST for 1 + 1
AST for (x + y) * (2 - z)
Values module encapsulates representation of values (e.g. Int vs. Integer) — flexibility for future
Map variable names to value
Look up value of variable in expression during evaluation
Given environment { x -> 5 }, expression x + 3 yields 8
Can use association list [("x",5)], Data.Map, etc.
Environments module encapsulates representation of environment (polymorphic) — flexibility for future
    import Values ( ValType, Name, defaultVal ) 
    type AnEnv a = [(Name,a)]
    newEnv     :: AnEnv a 
    toList     :: AnEnv a -> [(Name,a)]
    getBinding :: Name -> AnEnv a -> Maybe a 
    hasBinding :: Name -> AnEnv a -> Bool 
    newBinding :: Name -> a -> AnEnv a -> AnEnv a 
    setBinding :: Name -> a -> AnEnv a -> AnEnv a 
    bindList   :: [(Name,a)] -> AnEnv a -> AnEnv a From Evaluator module
Val c — constant (NumType) value c
Var n — value of variable n in current environment, gives error if not defined
Add l r — sum of values of expressions l, r
Sub l r — difference between values of expressions l, r
Mul l r — product of values of expressions l, r
Div l r — quotient of values of expressions l, r
Encapsulates semantics (evaluation function)
Exports evaluation function eval primarily
    import Values       ( ValType, Name, defaultVal )
    import AbSynCalc    ( Expr(..) )
    import Environments ( AnEnv, Name, newEnv, toList, getBinding,
                          hasBinding, newBinding, setBinding, bindList )
    type EvalErr = String
    type Env     = AnEnv ValType
    eval :: Expr -> Env -> Either EvalErr ValType
    eval (Val v) _   = Right v
    eval (Var n) env = 
        case getBinding n env of
            Nothing -> Left ("Undefined variable " ++ n)
            Just i  -> Right i
    eval (Add l r) env =
        case (eval l env, eval r env) of
            (Right lv, Right rv) -> Right (lv + rv)
            (Left le,  Left re ) -> Left (le ++ "\n" ++ re)
            (x@(Left le),  _   ) -> x
            (_,     y@(Left le)) -> y    eval (Sub l r) env = 
        case (eval l env, eval r env) of
            (Right lv, Right rv) -> Right (lv - rv)
            (Left le,  Left re ) -> Left (le ++ "\n" ++ re)
            (x@(Left le),  _   ) -> x
            (_,     y@(Left le)) -> y
    eval (Mul l r) env = 
        case (eval l env, eval r env) of
            (Right lv, Right rv) -> Right (lv * rv)
            (Left le,  Left re ) -> Left (le ++ "\n" ++ re)
            (x@(Left le),  _   ) -> x
            (_,     y@(Left le)) -> y
    eval (Div l r) env =
        case (eval l env, eval r env) of
            (Right _,  Right 0 ) -> Left "Division by 0"
            (Right lv, Right rv) -> Right (lv `div` rv)
            (Left le,  Left re ) -> Left (le ++ "\n" ++ re)
            (x@(Left le),  _   ) -> x
            (_,     y@(Left le)) -> ySimplify items based on operator properties to give faster execution, smaller trees (code improvement)
    simplify :: Expr -> Expr  -- parts left as exercise
    simplify (Add l r) =
        case (simplify l, simplify r) of
            (Val 0, rr)    -> rr
            (ll, Val 0)    -> ll
            (Val x, Val y) -> Val (x+y)
            (ll, rr)       -> Add ll rr
    simplify (Mul l r) =
        case (simplify l, simplify r) of
            (Val 0, rr)    -> Val 0
            (ll, Val 0)    -> Val 0
            (Val 1, rr)    -> rr
            (ll, Val 1)    -> ll
            (Val x, Val y) -> Val (x*y)
            (ll, rr)       -> Mul ll rr
    simplify t@(Var _) = t
    simplify t@(Val _) = tDerivative (probably should change ValType to Double to be practical)
Interpreter for simple ELI Calculator language
Abstract Synax module AbSynCalc
Values module Values
Environments module Environments
Evaluator module EvalCalc
Process AST module ProcessAST