programming in sml15150/resources/lectures/1/lecture1.pdf · javascript and python both have...
TRANSCRIPT
Lecture 1Principles of Functional Programming
Summer 2020
Programming in SML
Evaluation, Equivalence, Binding,Functions
Section 1
Functional Programming in SML
Jacob Neumann Programming in SML 19 May 2020 2 / 44
Functional programming vs. functional languages
Functional programming: a style of programming which avoids the useof mutable state and effects.Functional language: a programming language where state mutationand effects are not even possible.
In a functional language, it’s impossible not to use functionalprogramming. We teach this course in a functional language, so youhave to use functional programming.
You can do functional programming in non-functional languages (e.g.Javascript and Python both have functional programming utilities), andyou should! The goal of this course is to teach you to think functionally.That will help you even if you never touch a functional language again inyour life.
Jacob Neumann Programming in SML 19 May 2020 3 / 44
Standard ML
We teach this course in a language called Standard ML (SML).SML is:
Functional (for the most part)
Strongly-typed
Statically-scoped
Call-by-value, or “eager”
Modular
Jacob Neumann Programming in SML 19 May 2020 4 / 44
Computing in SML
Rather than thinking of computation as state mutations, we think ofcomputation as evaluation of expressions.
In this case, 217 is an expression, which we want to evaluate down toobtain 131072.
Jacob Neumann Programming in SML 19 May 2020 5 / 44
What’s 217?
Person 1: Hey, do you know what 217 is?Person 2: Yeah, it’s 217.Is Person 2 correct? Yes. Did they answer the question? No.
Person 1: Hey, do you know what 217 is?Person 2: Yeah, it’s 2× 216.Is Person 2 correct? Yes. Did they answer the question? Still no.
Jacob Neumann Programming in SML 19 May 2020 6 / 44
The goal of functional programming is to produce values
Moral of the previous slide: Computational queries (like “what’s217?”) come with a built-in notion of what counts as an answer: 217 and2× 216 aren’t acceptable answers to the question (whereas 131072 is anacceptable answer).
Functional programming has similar concepts:
An expression is a syntactically-well-formed piece of code
Some expressions are called values
Expressions can be evaluated (or “reduced”), perhaps producing avalue. If e is an expression which evaluates to a value v, weindicate this by either of the following notations:
e ↪→ v e =⇒ v
Jacob Neumann Programming in SML 19 May 2020 7 / 44
Stepping
Evaluating an expression down to a value takes place in a finite numberof discrete “steps”. We trace out evaluations like follows.
(3+2) *(9-6) =⇒ 5 * (9-6)
=⇒ 5 * 3
=⇒ 15
Each of these is “one step”. The notation e1 =⇒ e2 therefore meansthat evaluating e1 steps to e2 in some finite number of steps.
For all expressions e, e =⇒ e
If e1 =⇒ e2 and e2 =⇒ e3 then e1 =⇒ e3
Stepping “terminates” in values: if v is a value, then there is notsome v’ 6= v such that v =⇒ v’
Jacob Neumann Programming in SML 19 May 2020 8 / 44
Time to code!
You feed SML expressions, it tries to evaluate them, gives you back theresulting value (if it gets one)
Jacob Neumann Programming in SML 19 May 2020 9 / 44
Another way Person 2 could be unhelpful
Person 1: Hey, do you know what 217 is?Person 2: Yeah, it’s red.Here, Person 2 is just saying nonsense. Clearly, ‘red’ is not the correctanswer to what 217 is.
Moral: Queries like “what is 217? also come with implicit constraints onwhat kind of thing the answer is allowed to be. Note that ‘red’ might bea value, it’s just not the proper type of value.
Jacob Neumann Programming in SML 19 May 2020 10 / 44
Static Typechecking
Before attempting to evaluate an expression, SML will first checkwhether it is “well-typed”. This is done as the code is being compiled,which is before it is run.
What counts as “well-typed” is given by various rules called “typeinferences”.
If an expression e is well-typed, then that means there’s a type t suchthat “e is of type t”. This is written
e : t
Jacob Neumann Programming in SML 19 May 2020 11 / 44
int
int is a type
Each integer literal is a value of type int. 0:int, 17:int,∼23:int, etc.
If e:int, then ∼e:intIf e1:int and e2:int, then (e1+e2):int
If e1:int and e2:int, then (e1 * e2):int
If e1:int and e2:int, then (e1 - e2):int
If e1:int and e2:int, then (e1 div e2):int
Jacob Neumann Programming in SML 19 May 2020 12 / 44
string
string is a type
Each string literal is a value of type string . So"hello":string , "":string ,"mwef8892 cjqq" :string , etc.
If e1:string and e2:string , then (e1 ^ e2):string
If e:int, then Int.toString(e):string
Jacob Neumann Programming in SML 19 May 2020 13 / 44
bool
bool is a type
There are exactly two values of type bool , namely true:bool
and false:bool .
If e:bool , then (not e):bool .
If e1:bool and e2:bool , then (e1 orelse e2):bool and(e1 andalso e2):bool .
If t is any type and e1:t and e2:t and b:bool , then
(if b then e1 else e2) : t
If e1 and e2 are expressions of type int (or string , bool ,some other types), then
(e1 = e2) : bool
Jacob Neumann Programming in SML 19 May 2020 14 / 44
Check for understanding
Is this expression well-typed? If so, what’s its type? Does it have avalue?
if (3+3) =6 then "red" else 42
Is this expression well-typed? If so, what’s its type? Does it have avalue?
(if true then 5+5 else 7) = 1
Is this expression well-typed? If so, what’s its type? Does it have avalue?
1 div 0
Jacob Neumann Programming in SML 19 May 2020 15 / 44
Behavior
If I evaluate a well-typed expression e:t, exactly one of the threefollowing things happen:
1 e ↪→ v for some value v:t, e.g.1.0
1 2 ** 17
In this case, we call e valuable.
2 The evaluation of e loops forever and never reaches a value, e.g.1.1
1 2 ** ∼3
3 The evaluation of e “raises an exception”, e.g.1.2
1 1 div 0
This raises an SML exception called ‘Div‘. Exceptions arethemselves values, a fact we’ll cover next month.Jacob Neumann Programming in SML 19 May 2020 16 / 44
Extensional Equivalence
If I have two expressions e1 and e2 of the same type, it makes senseto ask whether they have the same behavior.
Given e1:t and e2:t, we say that e1 and e2 are extensionallyequivalent (written e1 ∼= e2) if one of the following holds:
There is some value v:t such that e1 ↪→ v and e2 ↪→ v
Both e1 and e2 loop forever when evaluated
Both e1 and e2 raise the same exception
Jacob Neumann Programming in SML 19 May 2020 17 / 44
Facts
∼= is an equivalence relation.
If e1 =⇒ e2, then e1 ∼= e2
The converse does not hold! e1 ∼= e2 does not imply e1 =⇒ e2
Referential Transparency: If e1 ∼= e2, then I can replace anyinstances of e1 with e2 (or vice versa) and obtain the same result.
Recall
max(L) # returned 4
max(L) # returned 0
Jacob Neumann Programming in SML 19 May 2020 18 / 44
pause for questions
Jacob Neumann Programming in SML 19 May 2020 19 / 44
Section 2
Bindings and Scope
Jacob Neumann Programming in SML 19 May 2020 20 / 44
val declarations
Often it’s helpful to give names to particular values, to be able to referto them later.
val x : t = e
What SML does with this syntax:
1 Checks that e is a well-typed expression of type t
2 Evaluates e
3 If evaluating e results in a value (call it v), SML binds the value v
to the variable name x.
We denote such a binding with the notation [v/x]. Note this is notvalid SML syntax, but mathematical notation about SML.
Jacob Neumann Programming in SML 19 May 2020 21 / 44
The environment
SML carries around all the bindings which have been made in theenvironment.1.3
1 val x : int = (3 * 6) + 1
2 val y : bool = true
3 val z : string = if y then Int.toString(x+1)
else "y was false"
4 val w : string = "M" ^ z
Jacob Neumann Programming in SML 19 May 2020 22 / 44
Evaluating with the environment
Environment:
Code:
val x : int = (3 * 6) + 1
Jacob Neumann Programming in SML 19 May 2020 23 / 44
Evaluating with the environment
Environment:
[19/x]
Code:
val y : bool = true
Jacob Neumann Programming in SML 19 May 2020 24 / 44
Evaluating with the environment
Environment:
[19/x][true/y]
Code:
val z : string = if y then Int.toString(x+1)
else "y was false"
Jacob Neumann Programming in SML 19 May 2020 25 / 44
Evaluating with the environment
Environment:
[19/x][true/y]["20"/z]
Code:
val w : string = "M" ^ z
Jacob Neumann Programming in SML 19 May 2020 26 / 44
Evaluating with the environment
Environment:
[19/x][true/y]["20"/z]["M20"/w]
Jacob Neumann Programming in SML 19 May 2020 27 / 44
Shadowing
What value gets bound to c? What about a? b?1.4
1 val a : int = 3
2 val b : int = a + a
3 val a : int = 9
4 val c : int = b - 2
Environment for Line 2
[3/a]
Environment for Line 4
[3/a][6/b][9/a]
Note: Don’t do this!
Jacob Neumann Programming in SML 19 May 2020 28 / 44
let expressions
1.5
1 val x : int = let
2 val y = 2
3 val z = y * y
4 in
5 3 + z
6 end
[7/x] is added to the environment, but [2/y] and [4/z] are not.
Jacob Neumann Programming in SML 19 May 2020 29 / 44
pause for questions
Jacob Neumann Programming in SML 19 May 2020 30 / 44
Section 3
Products and Functions
Jacob Neumann Programming in SML 19 May 2020 31 / 44
Product Types
If t1 is a type and t2 is a type, t1 * t2 is a type
If e1:t1 and e2:t2, then (e1 ,e2) : t1 * t2
If t1,t2, and t3 are types, t1 * t2 * t3 is a type
If e1:t1, e2:t2, and e3:t3, then(e1,e2,e3) : t1 * t2 * t3
and so on...
Note that (t1 * t2) * t3 is not the same as t1 * t2 * t3
Jacob Neumann Programming in SML 19 May 2020 32 / 44
Evaluation of tuples
(17+17+17 ,(2=2) andalso false)
=⇒ (51 ,(2=2) andalso false)
=⇒ (51,false andalso false)
=⇒ (51,false)
Note: The elements of the tuple are evaluated left-to-right.
Jacob Neumann Programming in SML 19 May 2020 33 / 44
Check for understanding
Suppose loop is an expression of type int which loops forever ifevaluated. Let loop2 be an expression of type int*int which loopsforever if evaluated.
Does the following extensional equivalence hold?
(loop , 1 div 0) ∼= loop2
How about this?
(1 div 0,loop) ∼= loop2
Jacob Neumann Programming in SML 19 May 2020 34 / 44
Functions
If t1 and t2 are types, t1 -> t2 is a type
If f:t1 -> t2 and e:t1, then (f e):t2
If e is any well-typed expression of type t2, then
(fn (x:t1) => e)
is a value of type t.
Functions are valuesFor example: (fn (x:string) => 2 + 2) is a value of typestring ->int. It does not evaluate to (fn (x:string) => 4)
Jacob Neumann Programming in SML 19 May 2020 35 / 44
Check for understanding
Is this expression well-typed? If so, what’s its type?
fn x => x div 0
Does this expression evaluate to a value? If so, what?
Is this expression well-typed? If so, what’s its type?
if true
then (fn x => x=2)
else (fn x => x andalso false)
Does this expression evaluate to a value? If so, what?
Jacob Neumann Programming in SML 19 May 2020 36 / 44
We’ve already seen many functions
val not : bool -> bool
val ∼ : int -> int
val (op +) : int * int -> int
val (op * ): int * int -> int
val (op ^ ): string * string -> string
Jacob Neumann Programming in SML 19 May 2020 37 / 44
Function evaluation
In order to evaluate an expression (e1 e2) (where e1:t1 ->t2 ande2:t1), SML
1 Evaluates e1 to some function value f (of the form fn x=>e)
2 Evaluates e2 to some value v
3 “Plugs v in for x in e”, and evaluates
(let val z = 2 in fn (x:bool) => z) (false)
=⇒ (fn (x:bool) =>[2/z]z) (false)
=⇒ [2/z][false/x]z
=⇒ 2
Jacob Neumann Programming in SML 19 May 2020 38 / 44
Functions and scoping
What value you think is bound to ??.1.6
1 val q : string = "yes"
2 val f : int -> string = fn (y:int) => q
3 val q : string = "no"
4 val ?? : string = f 2
Jacob Neumann Programming in SML 19 May 2020 39 / 44
Lots of fun
val exp = fn x => if x=0 then 1 else 2 * exp(x
-1)
The fun keyword allows you to declare a function which refers to itself1.7
1 fun exp (x:int):int = if x=0 then 1 else 2*exp
(x-1)
1.8
1 fun foo (x:int):int = 2 + foo(x)
Jacob Neumann Programming in SML 19 May 2020 40 / 44
5-Step Methodology
In this class, we’ll ask you to do all five of the following for whateverfunction you write.
1 Specify the type
2 Give a precondition (what you require to be true of the inputs)
3 Give a postcondition (a precise statement of what the functiondoes)
4 Implement the function
5 Provide test cases
Jacob Neumann Programming in SML 19 May 2020 41 / 44
1.9
1 (* double : int -> int
2 * REQUIRES: true
3 * ENSURES: double(n) == 2n
4 *)
5 fun double (n:int):int = n+n
6
7 val 0 = double 0
8 val 22 = double 11
9 val ∼12 = double ∼6
Jacob Neumann Programming in SML 19 May 2020 42 / 44
1.10
1 (* exp : int -> int
2 * REQUIRES: n>=0
3 * ENSURES: exp(n) == 2^n
4 *)
5 fun exp (0: int):int = 1
6 | exp (n:int):int = 2 * exp(n-1)
7
8 val 1 = exp 0
9 val 4 = exp 2
10 val 8 = exp 3
Jacob Neumann Programming in SML 19 May 2020 43 / 44
Thank you!
Jacob Neumann Programming in SML 19 May 2020 44 / 44