Midterm Review
Table of Contents
1. Midterm Review
1.1. Binder
A binder for example is x in the following function definition.
def func(x): #<--- here return x + 1
1.2. Lazy vs Eager
Example
f(x) = x + 2 f(3 * 4)
Eager (Call by value)
f(3 * 4)
= f(12)
= 12 + 2
= 14
Lazy (Call by name)
f(3 * 4)
= 3 * 4 + 2
= 12 + 2
= 14
Lazy can find the way to an answer while Eager errors.
Eager is better because we can point to where we should error.
Another Example
def f(x): print("f is called") return x + 3 def g(y): print("g is called") return y + 2 g(f(7))
In python f is called first because it is an eager langauge, but in a lazy language f(7) will not be firstly evaluated before it substitutes.
1.3. Curry
Originaly,
def f(a, b): . . . f(1, 2)
what if instead,
def f(a): def g(b): body return g f((1)(2))
Instead of having multiple arguments, why not have nested functions.
In theory we dont need function with multiple arguments.
Example In Racket
(define (f x y) (+ (* x x) (- y 5))) (define (curried-f x) (lambda (y) (+ (* x x) (- y 5))))) (f 10 20) ((curried-f 10) 20)
1.4. Lexical vs Dynamic Scope
def f(x): return x + y def g(y): return y - f(7) g(6)
Lexical Scope : be able to look at every binder and figure out the scope of each function where bindings arent shared between scopes in a sense
- usually how most languages work
- above code doesnt work
Dynamic Scope : the scope of bindings is shared with its children(s)
- seen as a mistake
- code might work depending on if binding exists
- above code does work
1.5. Substitution - Small Step Reduction Sequence
note: only time anything gets added to an environment is in function applications
Example
{{{(x) => {(y) => { + x y }}} 3} 7} -> at this point x and y are in the environment
= { {(y) => { + 3 y }} 7}
= {+ 3 7}
= 10