# Interpreting Functions --- CS 135 // 2021-04-15 ## Administrivia - MathCS talk on Friday + "A Tutorial on Designing Person-Centered Accessible Technologies" + Professor Meredith Moore + 2:00 to 3:00pm ## Assignment 2 - An individual assignment - Due Tuesday, 4/20 before class # Questions ## ...about anything? # A Basic Interpreter ## A Basic Interpreter - Recall that last time we implemented an interpreter for arithmetic - When adding subtraction to our language, we were able to do so via **desugaring** + Yes! `x-y = x + y*(-1)` - We didn't need to modify the core language and interpreter # Conditionals ## Adding Conditionals - We also added conditionals to our language ```lisp (if cnd thn els) ``` - Add a new Boolean data type + We can use `#t` for true and `#f` for false ## Adding Boolean Operators - Let's add operations for conjunction (logical and) and disjunction (logical or) - Can we do this with desugaring? + `(and x y)` is the same as `(if x y #f)` + `(or x y)` is the same as `(if x #t y)` - What about negation? + `(not x)` is the same as `(if x #f #t)` # Interpreting Functions ## Interpreting Functions - Let's add **functions** to our programming language - For simplicity, we will start with a C-like approach + Functions are defined **before** the `main` code + In other words, our `interp` function will be: ```haskell interp :: [FnDef] -> Expr -> Value ``` - To keep things simple, we will only consider functions with a single parameter ```haskell double x = x + x quadruple y = double (double y) const5 z = 5 ``` ## Parts of a Function Def ```haskell double x = x + x quadruple y = double (double y) const5 z = 5 ``` --- - What are the **parts** of a function definition? 1. A **function name** (e.g. `double`) 2. A **parameter name** (e.g. `x`) 3. A **body** (e.g. `x + x`) - What are the types of these parts? ## `FnDef` Type - We will start by defining a `FnDef` with these parts: ```haskell type Identifier = String data FnDef = FnDef { fnName :: Identifier , fnParam :: Identifier , fnBody :: Expr } ``` - Recall that `interp` takes a list of `FnDef`s and an `Expr` and then interprets `Expr` + Do we also need to change `Expr`? ## Extending `Expr` - We need to add two things to `Expr`: 1. We need **identifiers** since we need to process things like `x`, `y`, and `z` 2. We need **function application** to evaluate a function - Suppose I am **calling** a function ```haskell double 5 ``` - How many parts does function application have? ## Updated `Expr` - Our updated `Expr` type is now: ```haskell data Expr = Plus Expr Expr | Mult Expr Expr | Num Int | TrueE | FalseE | If Expr Expr Expr | Id Identifier | FnApp Identifier Expr -- fnName arg deriving Show ``` - In our `interp` function, what should we do when we encounter a `FnApp`? + We need to **substitute** the argument for the parameter in the body of the function ## The `subst` Function - We can define a function `subst` that substitutes the argument for the parameter in the body ```haskell subst :: Expr -> Identifier -> Expr -> Expr subst arg param body = case body of Plus x y -> Plus (subst arg param x) (subst arg param y) Mult x y -> Mult (subst arg param x) (subst arg param y) Num n -> Num n TrueE -> TrueE FalseE -> FalseE If cnd thn els -> If (subst arg param cnd) (subst arg param thn) (subst arg param els) FnApp f x -> FnApp f (subst arg param x) Id var -> if param == var then arg else Id var ``` ## Updated `interp` ```haskell interp :: [FnDef] -> Expr -> Value interp fns exp = case exp of Num n -> NumV n TrueE -> BoolV True FalseE -> BoolV False Plus x y -> binOp (+) (interp fns x) (interp fns y) Mult x y -> binOp (*) (interp fns x) (interp fns y) If cnd thn els -> case interp fns cnd of BoolV True -> interp fns thn BoolV False -> interp fns els _ -> error "*** not a Bool" FnApp f x -> let (FnDef _ param body) = lookupFn f fns in interp fns (subst x param body) Id ident -> error "*** unbound identifier" ```