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
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)) -> y
Simplify 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 _) = t
Derivative (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