LISP: designed by John McCarthy, 1958 published 1960 Introduc)on to Racket, a dialect of LISP: Expressions and Declara)ons

CS251 Programming Languages Spring 2019, Lyn Turbak

Department of Computer Science Wellesley College

These slides build on Ben Wood’s Fall ‘15 slides Expr/decl 2

LISP: implemented by Steve Russell, LISP: LISt Processing early 1960s • McCarthy, MIT arNficial intelligence, 1950s-60s – Advice Taker: represent logic as data, not just program Emacs: M-x doctor • Needed a language for: – Symbolic computaNon i.e., not just number crunching – Programming with logic – ArNficial intelligence – Experimental programming

• So one!

Expr/decl 3 Expr/decl 4 Scheme • Gerald Jay Sussman and Guy Lewis Steele (mid 1970s) • Grandchild of LISP (variant of Scheme) • Lexically-scoped dialect of LISP – Some changes/improvements, quite similar that arose from trying to make • Developed by the PLT group an “actor” language. (haps://racket-lang.org/people.html), the same folks • Described in amazing “Lambda the UlNmate” created DrJava. papers (hap://library.readscheme.org/page1.html) • Why study Racket in CS251? – Lambda the UlNmate PL blog inspired by these: – Clean slate, unfamiliar hap://lambda-the-ulNmate.org – • Led to Structure and InterpretaNon Careful study of PL foundaNons (“PL mindset”) of Computer Programs (SICP) and – FuncNonal programming paradigm MIT 6.001 (haps://mitpress.mit.edu/sicp/) • Emphasis on funcNons and their composiNon • Immutable data (lists) – Beauty of minimalism – Observe design constraints/historical context Expr/decl 5 Expr/decl 6

Expressions, Values, and DeclaraNons Values • Values are expressions that cannot be evaluated • EnNre language: these three things further.

• Syntax: • Expressions have evalua6on rules: – Numbers: 251, 240, 301 – How to determine the value denoted by an expression. – Booleans: #t, #f – There are values we will meet soon • For each structure we add to the language: (, symbols, lists, funcNons, …) – What is its syntax? How is it wriaen? • EvaluaNon rule: – What is its evalua)on rule? How is it evaluated to a – Values evaluate to themselves. value (expression that cannot be evaluated further)?

Expr/decl 7 Expr/decl 8 AddiNon expression: syntax AddiNon expression: evaluaNon

Adds two numbers together. Syntax: (+ E1 E2)

Note recursive Syntax: (+ E1 E2) Every parenthesis required; none may be omiaed. EvaluaNon rule: structure! E1 and E2 stand in for any expression. 1. Evaluate E1 to a value V1 Note prefix notaNon. Note recursive 2. Evaluate E2 to a value V2

Examples: structure! 3. Return the arithmeNc of V1 + V2. (+ 251 240) (+ (+ 251 240) 301) (+ #t 251) Not quite!

Expr/decl 9 Expr/decl 10

AddiNon: dynamic checking EvaluaNon AsserNons Formalize EvaluaNon Syntax: (+ E1 E2) The evalua)on asser)on notaNon E ↓ V means S)ll not quite! ``E evaluates to V ’’. EvaluaNon rule: More later … Our evaluaNon rules so far: 1. evaluate E1 to a value V1 • value rule: V ↓ V (where V is a number or boolean) 2. Evaluate E2 to a value V2 • addi6on rule: 3. If V1 and V2 are both numbers then if E1 ↓ V1 and E2 ↓ V2 return the arithmeNc sum of V1 + V2. and V1 and V2 are both numbers 4. Otherwise, a type error occurs. and V is the sum of V1 and V2 then (+ E1 E2) ↓ V Dynamic type-checking

Expr/decl 11 Expr/decl 12 EvaluaNon DerivaNon in English More Compact DerivaNon NotaNon An evalua)on deriva)on is a ``proof ’’ that an expression V ↓ V [value rule] E1 ↓ V1 evaluates to a value using the evaluaNon rules. E2 ↓ V2 whereVis a value [addiNon rule] ↓ (+ 3 (+ 5 4)) 12 by the addiNon rule because: (number, boolean, etc.) (+ E1 E2) ↓ V • 3 ↓ 3 by the value rule

side condiNons of rules Where V1 and V2 are numbers and • (+ 5 4) ↓ 9 by the addiNon rule because: V is the sum of V1 and V2. – 5 ↓ 5 by the value rule ↓ [value] – ↓ by the value rule 3 3 4 4 – 5 and 4 are both numbers 5 ↓ 5 [value]

– 9 is the sum of 5 and 4 4 ↓ 4 [value] [addiNon] • 3 and 9 are both numbers (+ 5 4) ↓ 9 [addiNon] • 12 is the sum of 3 and 9 (+ 3 (+ 5 4)) ↓ 12

Expr/decl 13 Expr/decl 14

Errors Are Modeled by “Stuck” DerivaNons SyntacNc Sugar for AddiNon

The addiNon operator + can take any number of operands. How to evaluate How to evaluate • For now, treat (+ E1 E2 … En)as (+ (+ E1 E2) … En) (+ #t (+ 5 4))? (+ (+ 1 2) (+ 5 #f))? E.g., treat (+ 7 2 -5 8) as (+ (+ (+ 7 2) -5) 8) #t ↓ #t [value] 1 ↓ 1 [value] • Treat (+ E)as E (or say if E ↓ V then (+ E) ↓ V) 5 ↓ 5 [value] 2 ↓ 2 [value] • Treat (+) as 0 (or say (+)↓ 0 ) 4 ↓ 4 [value] (+ 1 2) ↓ 3 [addiNon] [addiNon] • (+ 5 4) ↓ 9 5 ↓ 5 [value] This approach is known as syntac)c sugar: introduce new syntacNc forms that “desugar” into exisNng ones. Stuck here. Can’t apply #f ↓ #f [value] (addiNon) rule because • In this case, an alternaNve approach would be to introduce #t is not a number in Stuck here. Can’t apply (addiNon) rule because more complex evaluaNon rules when + has a number of (+ #t 9) #f is not a number in arguments different from 2. (+ 5 #f)

Expr/decl 15 Expr/decl 16

Other ArithmeNc Operators RelaNon Operators Similar syntax and evaluaNon for The following relaNonal operators on numbers return - * / quotient remainder min max booleans: < <= = >= > except: • Second argument of /, quotient, remainder must be nonzero For example: • Result of / is a raNonal number (fracNon) when both values are integers. (It is a floaNng point number if least one value ↓ is a float.) E1 V1 E2 ↓ V2 • quotient and remainder take exactly two arguments; [ than] anything else is an error. (< E1 E2) ↓ V • (- E) is treated as (- 0 E) • (/ E) is treated as (/ 1 E) Where V1 and V2 are numbers and V is #t if V1 is less than V2 • (min E) and (max E) treated as E or #f if V1 is not less than V2 • (*) evaluates to 1. • (/), (-), (min) , (max) are errors (i.e., stuck)

Expr/decl 17 Expr/decl 18

CondiNonal (if) expressions DerivaNon-style rules for CondiNonals

Syntax: (if Etest Ethen Eelse) Etest ↓ Vtest Eelse is not Ethen ↓ Vthen [if nonfalse] evaluated! EvaluaNon rule: (if Etest Ethen Eelse) ↓ Vthen 1. Evaluate Etest to a value Vtest. Where Vtest is not #f 2. If Vtest is not the value #f then return the result of evaluaNng Ethen Etest ↓ #f otherwise Eelse ↓ Velse Ethen is not return the result of evaluaNng Eelse [if false] Etest Ethen Eelse ↓ Velse evaluated! (if )

Expr/decl 19 Expr/decl 20

Your turn Expressions vs. statements Use evaluaNon derivaNons to evaluate the CondiNonal expressions can go anywhere an following expressions expression is expected:

(if (< 8 2) (+ #f 5) (+ 3 4)) (+ 4 (* (if (< 9 (- 251 240)) 2 3) 5))

(if (if (< 1 2) (> 4 3) (> 5 6)) (if (+ 1 2) (- 3 7) (/ 9 0)) (+ 7 8) (* 9 10) (+ (if (< 1 2) (* 3 4) (/ 5 6)) 7) Note: if is an expression, not a statement. Do (+ (if 1 2 3) #t) other languages you know have condiNonal expressions in addiNon to condiNonal statements? (Many do! Java, JavaScript, Python, …) Expr/decl 21 Expr/decl 22

Design choice in condiNonal semanNcs CondiNonal expressions: careful! In the [if nonfalse] rule, Vtest is not required to be a boolean!

Unlike earlier expressions, not all Etest ↓ Vtest Ethen ↓ Vthen subexpressions of if expressions are evaluated! [if nonfalse] (if Etest Ethen Eelse) ↓ Vthen Where Vtest is not #f (if (> 251 240) 251 (/ 251 0)) This is a design choice for the language designer. What would happen if we replace the above rule by

Etest ↓ #t (if #f (+ #t 240) 251) ↓ Ethen Vthen [if true] (if Etest Ethen Eelse) ↓ Vthen

This design choice is related to noNons of “truthiness” and

Expr/decl 23 “falsiness” that you will explore in PS2. Expr/decl 24

Environments: MoNvaNon Environments: DefiniNon Want to be able to name values so can refer to • An environment is a sequence of bindings that them later by name. E.g.; associate idenNfiers (variable names) with values. – Concrete example: (define x (+ 1 2)) num ⟼ 17, absoluteZero ⟼ -273, true ⟼#t – Abstract Example (use Id to range over idenNfiers = names): (define y (* 4 x)) Id1 ⟼ V1, Id2 ⟼ V2, …, Idn ⟼ Vn – Empty environment: ∅ (define (- y x)) • An environment serves as a context for evaluaNng (define (< x diff)) expressions that contain idenNfiers. • Second argument to evaluaNon, takes both an (if test (+ (* x y) diff) 17) expression and an environment.

Expr/decl 25 Expr/decl 26

AddiNon: evaluaNon with references Syntax: Id Syntax: (+ E1 E2) Id: any iden6fier EvaluaNon rule: Look up and return the value to which Id is bound in the current EvaluaNon rule: environment. • Look-up proceeds by searching from the -recently added 1. evaluate E1 in the current environment to a value V1 bindings to the least-recently added bindings (front to back in our 2. Evaluate E2 in the current environment to a value V2 representaNon) • If Id is not bound in the current environment, evaluaNng it is “stuck” 3. If V1 and V2 are both numbers then at an unbound variable error. return the arithmeNc sum of V1 + V2. Examples: 4. Otherwise, a type error occurs. • Suppose is num ⟼ 17, absZero ⟼ -273, true ⟼ #t, num ⟼ 5 • In env, num evaluates to 17 (more recent than 5), absZero evaluates to -273, and true evaluates to #t. Any other name is stuck.

Expr/decl 27 Expr/decl 28

define DeclaraNons Environments: Example env0 = ∅ (can as . in text) Syntax: (define Id E) (define x (+ 1 2)) define: keyword env1 = x ⟼ 3, ∅ (abbreviated x ⟼ 3; can write as x -> 3 in text) Id: any iden6fier (define y (* 4 x)) E: any expression env2 = y ⟼ 12, x ⟼ 3 (most recent binding 2irst) This is a declara)on, not an expression! (define diff (- y x)) We will say a declara)ons are processed, not evaluated env3 = diff ⟼ 9, y ⟼ 12, x ⟼ 3

(define test (< x diff)) Processing rule: env4 = test ⟼ #t, diff ⟼ 9, y ⟼ 12, x ⟼ 3 1. Evaluate E to a value V in the current environment 2. Produce a new environment that is idenNcal to the (if test (+ (* x 5) diff) 17) current environment, with the addiNonal binding environment here is sNll env4 Id → V at the front. Use this new environment as the current environment going forward. (define x (* x y)) env5 = x ⟼ 36, test ⟼ #t, diff ⟼ 9, y ⟼ 12, x ⟼ 3 Expr/decl 29 Note that binding x ⟼ 36 “shadows” x ⟼ 3 , making it inaccessible Expr/decl 30

EvaluaNon AsserNons & Rules with Environments Example DerivaNon with Environments The evalua)on asser)on notaNon E # env ↓ V means ``EvaluaNng expression E in environment env yields value V ’’. Suppose env4 = test ⟼ #t, diff ⟼ 9, y ⟼ 12, x ⟼ 3

Id # env ↓ V [varref] E1 # env ↓ V1 test # env4 ↓ #t [varref] Where Id is an idenNfier and E2 # env ↓ V2 x # env4 ↓ 3 [varref] Id ⟼ V is the first binding in [addiNon] env for Id Only this rule actually (+ E1 E2) # env ↓ V 5 # env4 ↓ 5 [value] uses env; others just [mulNplicaNon] pass it along (* x 5) # env4 ↓ 15 Where V1 and V2 are numbers and V is the sum of V1 and V2. Rules for other diff # env4 ↓ 9 [varref] V # env ↓ V [value] arithmeNc and relaNonal ops are similar. [addiNon] (+ (* x 5) diff)# env4 ↓ 24 where V is a value [if nonfalse] (number, boolean, etc.) E1 # env ↓ V1 (if test (+ (* x 5) diff) 17)# env4 ↓ 24 E2 # env ↓ V2 E1 # env ↓ #f [if nonfalse] E3 # env ↓ V3 [if false] (if E1 E2 E3) # env ↓ V2 (if E1 E2 E3) # env ↓ V3 Where V1 is not #f Expr/decl 31 Expr/decl 32

Conclusion-below-subderivaNons, in text Conclusion-above-subderivaNons, with bullets

Suppose env4 = test -> #t, diff -> 9, y -> 12, x -> 3 Suppose env4 = test -> #t, diff -> 9, y -> 12, x -> 3

| test # env4 ↓ #t [varref] (if test (+ (* x 5) diff) 17)# env4 ↓ 24 [if nonfalse] | | | x # env4 ↓ 3 [varref] q test # env4 ↓ #t [varref] | | | 5 # env4 ↓ 5 [value] | | ------[multiplication] q (+ (* x 5) diff)# env4 ↓ 24 [addition] | | (* x 5) # env4 ↓ 15 o (* x 5) # env4 ↓ 15 [multiplication] | | diff # env4 ↓ 9 [varref] § x # env4 ↓ 3 [varref] | | ------[addition] § 5 # env4 ↓ 5 [value] | (+ (* x 5) diff)# env4 ↓ 24 ------[if nonfalse] o diff # env4 ↓ 9 [multiplication] (if test (+ (* x 5) diff) 17)# env4 ↓ 24

Expr/decl 33 Expr/decl 34

Formalizing definiNons Threading environments through definiNons

The declara)on asser)on notaNon(define Id E) # env ⇓ env’ 2 # ↓ 2 [value] means ``Processing the definiNon Id E in environment (define ) 3 # ↓ 3 [value] env yields a new environment env’ ’’. We use a different arrow, ⇓, [addiNon] (+ 2 3)# ↓ 5 to emphasize that definiNons are not evaluated to values, but [define] processed to environments. (define a (+ 2 3))# ⇓ a ⟼ 5

a # a ⟼ 5 ↓ 5 [varref] E # env ↓ V [define] a # a ⟼ 5 ↓ 5 [varref] (define Id E)# env ⇓ Id ⟼ V, env [mulNplicaNon] (* a a)# a ⟼ 5 ↓ 25 [define] ⟼ ⟼ ⟼ (define b (* a a))# a 5 ⇓ b 25, a 5

b # b ⟼ 25, a ⟼ 5 ↓ 25 [varref]

a # b ⟼ 25, a ⟼ 5 ↓ 5 [varref] [subtracNon] (- b a)# b ⟼ 25, a ⟼ 5 ↓ 20 Expr/decl 35 Expr/decl 36

Racket IdenNfiers Small-step vs. big-step semanNcs The evaluaNon derivaNons we’ve seen so far are called a big-step seman)cs • Racket idenNfiers are case sensiNve. The following are four different idenNfiers: ABC, Abc, aBc, abc because the derivaNon e # env2 ↓ v explains the evaluaNon of e to v as one “big step” jusNfied by the evaluaNon of its subexpressions.

• Unlike most languages, Racket is very liberal with its definiNon of legal An alternaNve way to express evaluaNon is a small-step seman)cs in which an idenNfers. Preay much any character sequence is allowed as expression is simplified to a value in a sequence of steps that simplifies idenNfier with the following excepNons: subexpressions. You do this all the Nme when simplifying math expressions, and – Can’t contain whitespace we can do it in Racket, too. E.g; – Can’t contain special characters ()[]{}”,’`;#|\ – Can’t have same syntax as a number (- (* (+ 2 3) 9) (/ 18 6))

• This means variable names can use (and even begin with) digits and ⇒ (- (* 5 9) (/ 18 6)) characters like !@$%^&*.-+_:<=>?/ E.g.: – myLongName, my_long__name, my-long-name ⇒ (- 45 (/ 18 6)) – is_a+b

Expr/decl 37 Expr/decl 38

Small-step semanNcs: intuiNon Small-step semanNcs: reducNon rules There are a small number of reducNon rules for Racket. These specify the Scan lew to right to find the first redex (nonvalue subexpression that can be reduced to a redexes of the language and how to reduce them. value) and reduce it: The rules owen require certain subparts of a redex to be (parNcular kinds of) (- (* (+ 2 3) 9) (/ 18 6)) values in order to be applicable. ⇒ (- (* 5 9) (/ 18 6)) [addition] Id ⇒ V , where Id ⟼ V is the first binding for Id ⇒ (- 45 (/ 18 6)) [multiplication] in the current environment* [varref] (+ V1 V2)⇒ V, where V is the sum of numbers V1 and V2 [addiNon] ⇒ (- 45 3) [division] There are similar rules for other arithmeNc/relaNonal operators [subtraction] ⇒ 42 (if Vtest Ethen Eelse ) ⇒ Ethen, if Vtest is not #f [if nonfalse] (if #f Ethen Eelse ) ⇒ Eelse [if false]

* In a more formal approach, the notaNon would make the environment explicit. E.g., E # env ⇒ V Expr/decl 39 Expr/decl 40 Small-step semanNcs: condiNonal example Small-step semanNcs: errors as stuck expressions (+ (if {(< 1 2)} (* 3 4) (/ 5 6)) 7) Similar to big-step semanNcs, we model errors (dynamic type errors, divide by => (+ {(if #t (* 3 4) (/ 5 6))} 7) [less than] zero, etc.) in small-step semanNcs as expressions in which the evaluaNon process ⇒ (+ {(* 3 4)} 7) [if nonfalse] is stuck because no reducNon rule is matched. For example: ⇒ {(+ 12 7)} [multiplication] (- (* (+ 2 3) #t) (/ 18 6)) ⇒ 19 [addition] ⇒ (- (* 5 #t) (/ 18 6)) Stuck!

Notes for wriNng derivaNons in text: (if (= 2 (/ (+ 3 4) (- 5 5))) 8 9) o You can use => for ⇒ ⇒ (if (= 2 (/ 7 (- 5 5))) 8 9)

o Use curly braces {…} to mark the redex ⇒ (if (= 2 (/ 7 0)) 8 9) Stuck! o Use square brackets to name the rule used to reduce the redex from the previous line to the current line.

Expr/decl 41 Expr/decl 42

Small-step semanNcs: your turn Racket DocumentaNon Use small-step semanNcs to evaluate the following expressions:

Racket Guide: (if (< 8 2) (+ #f 5) (+ 3 4)) haps://docs.racket-lang.org/guide/ (if (+ 1 2) (- 3 7) (/ 9 0)) (+ (if (< 1 2) (* 3 4) (/ 5 6)) 7) Racket Reference: haps://docs.racket-lang.org/reference (+ (if 1 2 3) #t)

Expr/decl 43 Expr/decl 44