CSE 341 : Programming Languages

Similar documents
CSci 4223 Principles of Programming Languages

CSci 4223 Lecture 12 March 4, 2013 Topics: Lexical scope, dynamic scope, closures

CSE341: Programming Languages Lecture 9 Function-Closure Idioms. Dan Grossman Winter 2013

CSE341: Programming Languages Lecture 9 Function-Closure Idioms. Dan Grossman Fall 2011

CSE341: Programming Languages Winter 2018 Unit 3 Summary Zach Tatlock, University of Washington

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

CSE 341 Section 5. Winter 2018

Racket. CSE341: Programming Languages Lecture 14 Introduction to Racket. Getting started. Racket vs. Scheme. Example.

CSE341: Programming Languages Lecture 6 Nested Patterns Exceptions Tail Recursion. Zach Tatlock Winter 2018

CSE341: Programming Languages Lecture 4 Records, Datatypes, Case Expressions. Dan Grossman Spring 2013

CSE341: Programming Languages Lecture 7 First-Class Functions. Dan Grossman Winter 2013

Recap: Functions as first-class values

The Environment Model. Nate Foster Spring 2018

CSE3322 Programming Languages and Implementation

CSE341, Fall 2011, Midterm Examination October 31, 2011

CSE 341: Programming Languages

Preparing for Class: Watch le Videos! What is an ML program?

CS Lecture 6: Map and Fold. Prof. Clarkson Spring Today s music: Selections from the soundtrack to 2001: A Space Odyssey

CSE341: Programming Languages Lecture 17 Implementing Languages Including Closures. Dan Grossman Autumn 2018

CSE341 Section 3. Standard-Library Docs, First-Class Functions, & More

CSE341: Programming Languages Lecture 11 Type Inference. Dan Grossman Spring 2016

CSE341, Spring 2013, Final Examination June 13, 2013

CSE341 Spring 2016, Midterm Examination April 29, 2016

CS152: Programming Languages. Lecture 7 Lambda Calculus. Dan Grossman Spring 2011

The Environment Model

CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists. Zach Tatlock Winter 2018

Function definitions. CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists. Example, extended. Some gotchas. Zach Tatlock Winter 2018

What is a macro. CSE341: Programming Languages Lecture 15 Macros. Example uses. Using Racket Macros. Zach Tatlock Winter 2018

CSE341: Programming Languages Lecture 15 Macros. Zach Tatlock Winter 2018

News. CSE 130: Programming Languages. Environments & Closures. Functions are first-class values. Recap: Functions as first-class values

CSE 341: Programming Languages

CSE341, Fall 2011, Midterm Examination October 31, 2011

CSE341: Programming Languages Lecture 19 Introduction to Ruby and OOP. Dan Grossman Winter 2013

CSE341 Autumn 2017, Final Examination December 12, 2017

CSE341 Spring 2017, Midterm Examination April 28, 2017

Ruby logistics. CSE341: Programming Languages Lecture 19 Introduction to Ruby and OOP. Ruby: Not our focus. Ruby: Our focus. A note on the homework

CSE 341: Programming Languages

CSci 4223 Principles of Programming Languages

CSE341 Spring 2016, Midterm Examination April 29, 2016

CMSC 330: Organization of Programming Languages. OCaml Higher Order Functions

CSE 341: Programming Languages

News. Programming Languages. Complex types: Lists. Recap: ML s Holy Trinity. CSE 130: Spring 2012

CSE 341 : Programming Languages Midterm, Spring 2015

CSE413: Programming Languages and Implementation Racket structs Implementing languages with interpreters Implementing closures

CS422 - Programming Language Design

Typical workflow. CSE341: Programming Languages. Lecture 17 Implementing Languages Including Closures. Reality more complicated

CSC324- TUTORIAL 5. Shems Saleh* *Some slides inspired by/based on Afsaneh Fazly s slides

CS Lecture 6: Map and Fold. Prof. Clarkson Fall Today s music: Selections from the soundtrack to 2001: A Space Odyssey

Warm-up and Memoization

CSE341 Autumn 2017, Midterm Examination October 30, 2017

Announcements. Scope, Function Calls and Storage Management. Block Structured Languages. Topics. Examples. Simplified Machine Model.

Whereweare. CS-XXX: Graduate Programming Languages. Lecture 7 Lambda Calculus. Adding data structures. Data + Code. What about functions

Variables and Bindings

CMSC 330: Organization of Programming Languages. OCaml Higher Order Functions

CSE 341, Spring 2011, Final Examination 9 June Please do not turn the page until everyone is ready.

Project 2: Scheme Interpreter

CPL 2016, week 10. Clojure functional core. Oleg Batrashev. April 11, Institute of Computer Science, Tartu, Estonia

CMSC 330: Organization of Programming Languages. OCaml Higher Order Functions

Some Advanced ML Features

Booleans (aka Truth Values) Programming Languages and Compilers (CS 421) Booleans and Short-Circuit Evaluation. Tuples as Values.

Part I: Written Problems

CSE341: Programming Languages Winter 2018 Unit 5 Summary Zach Tatlock, University of Washington

Programming Language Concepts, cs2104 Lecture 04 ( )

Programming Languages

Begin at the beginning

OCaml. ML Flow. Complex types: Lists. Complex types: Lists. The PL for the discerning hacker. All elements must have same type.

CSE 413 Languages & Implementation. Hal Perkins Winter 2019 Structs, Implementing Languages (credits: Dan Grossman, CSE 341)

Late Binding; OOP as a Racket Pattern

CSE341: Programming Languages Lecture 20 Arrays and Such, Blocks and Procs, Inheritance and Overriding. Dan Grossman Spring 2017

CMSC 330: Organization of Programming Languages. Functional Programming with Lists

FUNCTIONAL PROGRAMMING

CMSC 330, Fall 2013, Practice Problems 3

Let s Get Functional. Learn You Some Erlang for Great Good! 2013, Fred Hébert

G Programming Languages - Fall 2012

INF 102 CONCEPTS OF PROG. LANGS FUNCTIONAL COMPOSITION. Instructors: James Jones Copyright Instructors.

Homework 5. Notes. Turn-In Instructions. Reading. Problems. Handout 19 CSCI 334: Spring (Required) Read Mitchell, Chapters 6 and 7.

CMSC 330, Fall 2013, Practice Problem 3 Solutions

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler Front-End

Side note: Tail Recursion. Begin at the beginning. Side note: Tail Recursion. Base Types. Base Type: int. Base Type: int

Tail Recursion: Factorial. Begin at the beginning. How does it execute? Tail recursion. Tail recursive factorial. Tail recursive factorial

INF 212 ANALYSIS OF PROG. LANGS FUNCTION COMPOSITION. Instructors: Crista Lopes Copyright Instructors.

max function Next concat function max function What s the pattern? concat function More on recursion Higher-order functions

Racket: Macros. Advanced Functional Programming. Jean-Noël Monette. November 2013

Programming Languages

# true;; - : bool = true. # false;; - : bool = false 9/10/ // = {s (5, "hi", 3.2), c 4, a 1, b 5} 9/10/2017 4

CSE341 Spring 2016, Final Examination June 6, 2016

CSE341: Programming Languages Lecture 26 Course Victory Lap. Dan Grossman Spring 2016

Every language has its own scoping rules. For example, what is the scope of variable j in this Java program?

Smalltalk: developed at Xerox Palo Alto Research Center by the Learning Research Group in the 1970 s (Smalltalk-72, Smalltalk-76, Smalltalk-80)

Scope, Functions, and Storage Management

Programming Languages and Compilers (CS 421)

Environments

A Second Look At ML. Chapter Seven Modern Programming Languages, 2nd ed. 1

Programming Languages

CSE 505: Concepts of Programming Languages

To figure this out we need a more precise understanding of how ML works

CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists. Dan Grossman Fall 2011

Bindings & Substitution

CSE 505: Programming Languages. Lecture 10 Types. Zach Tatlock Winter 2015

Transcription:

CSE 341 : Programming Languages Lecture 9 Lexical Scope, Closures Zach Tatlock Spring 2014

Very important concept We know function bodies can use any bindings in scope But now that functions can be passed around: In scope where? Where the function was defined (not where it was called) This semantics is called lexical scope There are lots of good reasons for this semantics (why) Discussed after explaining what the semantics is (what) Later in course: implementing it (how) Must get this for homework, exams, and competent programming 2

Example Demonstrates lexical scope even without higher-order functions: (* 1 *) val x = 1 (* 2 *) fun f y = x + y (* 3 *) val x = 2 (* 4 *) val y = 3 (* 5 *) val z = f (x + y) Line 2 defines a function that, when called, evaluates body x+y in environment where x maps to 1 and y maps to the argument Call on line 5: Looks up f to get the function defined on line 2 Evaluates x+y in current environment, producing 5 Calls the function with 5, which evaluates the body in the old environment, producing 6 3

Closures How can functions be evaluated in old environments that aren t around anymore? The language implementation keeps them around as necessary Can define the semantics of functions as follows: A function value has two parts The code (obviously) The environment that was current when the function was defined This is a pair but unlike ML pairs, you cannot access the pieces All you can do is call this pair This pair is called a function closure A call evaluates the code part in the environment part (extended with the function argument) 4

Example (* 1 *) val x = 1 (* 2 *) fun f y = x + y (* 3 *) val x = 2 (* 4 *) val y = 3 (* 5 *) val z = f (x + y) Line 2 creates a closure and binds f to it: Code: take y and have body x+y Environment: x maps to 1 (Plus whatever else is in scope, including f for recursion) Line 5 calls the closure defined in line 2 with 5 So body evaluated in environment x maps to 1 extended with y maps to 5 5

Coming up: Now you know the rule: lexical scope Next steps: (Silly) examples to demonstrate how the rule works with higherorder functions Why the other natural rule, dynamic scope, is a bad idea Powerful idioms with higher-order functions that use this rule Passing functions to iterators like filter Next lecture: Several more idioms 6

The rule stays the same A function body is evaluated in the environment where the function was defined (created) Extended with the function argument Nothing changes to this rule when we take and return functions But the environment may involve nested let-expressions, not just the top-level sequence of bindings Makes first-class functions much more powerful Even if may seem counterintuitive at first 7

Example: Returning a function Trust the rule: Evaluating line 4 binds to g to a closure: Code: take z and have body x+y+z Environment: y maps to 4, x maps to 5 (shadowing), So this closure will always add 9 to its argument So line 6 binds 15 to z (* 1 *) val x = 1 (* 2 *) fun f y = (* 2a *) let val x = y+1 (* 2b *) in fn z => x+y+z end (* 3 *) val x = 3 (* 4 *) val g = f 4 (* 5 *) val y = 5 (* 6 *) val z = g 6 8

Example: Passing a function (* 1 *) fun f g = (* call arg with 2 *) (* 1a *) let val x = 3 (* 1b *) in g 2 end (* 2 *) val x = 4 (* 3 *) fun h y = x + y (* 4 *) val z = f h Trust the rule: Evaluating line 3 binds h to a closure: Code: take y and have body x+y Environment: x maps to 4, f maps to a closure, So this closure will always add 4 to its argument So line 4 binds 6 to z Line 1a is as stupid and irrelevant as it should be 9

Why lexical scope Lexical scope: use environment where function is defined Dynamic scope: use environment where function is called Decades ago, both might have been considered reasonable, but now we know lexical scope makes much more sense Here are three precise, technical reasons Not a matter of opinion 10

Why lexical scope? 1. Function meaning does not depend on variable names used Example: Can change body of f to use q everywhere instead of x Lexical scope: it cannot matter Dynamic scope: depends how result is used fun f y = let val x = y+1 in fn z => x+y+z end Example: Can remove unused variables Dynamic scope: but maybe some g uses it (weird) fun f g = let val x = 3 in g 2 end 11

Why lexical scope? 2. Functions can be type-checked and reasoned about where defined Example: Dynamic scope tries to add a string and an unbound variable to 6 val x = 1 fun f y = let val x = y+1 in fn z => x+y+z end val x = "hi" val g = f 7 val z = g 4 12

Why lexical scope? 3. Closures can easily store the data they need Many more examples and idioms to come fun greaterthanx x = fn y => y > x fun filter (f,xs) = case xs of [] => [] x::xs => if f x then x::(filter(f,xs)) else filter(f,xs) fun nonegatives xs = filter(greaterthanx ~1, xs) fun allgreater (xs,n) = filter(fn x => x > n, xs) 13

Does dynamic scope exist? Lexical scope for variables is definitely the right default Very common across languages Dynamic scope is occasionally convenient in some situations So some languages (e.g., Racket) have special ways to do it But most do not bother If you squint some, exception handling is more like dynamic scope: raise e transfers control to the current innermost handler Does not have to be syntactically inside a handle expression (and usually is not) 14

When things evaluate Things we know: A function body is not evaluated until the function is called A function body is evaluated every time the function is called A variable binding evaluates its expression when the binding is evaluated, not every time the variable is used With closures, this means we can avoid repeating computations that do not depend on function arguments Not so worried about performance, but good example to emphasize the semantics of functions 15

Recomputation These both work and rely on using variables in the environment fun allshorterthan1 (xs,s) = filter(fn x => String.size x < String.size s, xs) fun allshorterthan2 (xs,s) = let val i = String.size s in filter(fn x => String.size x < i, xs) end The first one computes String.size once per element of xs The second one computes String.size s once per list Nothing new here: let-bindings are evaluated when encountered and function bodies evaluated when called 16

Another famous function: Fold fold (and synonyms / close relatives reduce, inject, etc.) is another very famous iterator over recursive structures Accumulates an answer by repeatedly applying f to answer so far fold(f,acc,[x1,x2,x3,x4]) computes f(f(f(f(acc,x1),x2),x3),x4) fun fold (f,acc,xs) = case xs of [] => acc x::xs => fold(f, f(acc,x), xs) This version folds left ; another version folds right Whether the direction matters depends on f (often not) val fold = fn : ('a * 'b -> 'a) * 'a * 'b list -> 'a 17

Why iterators again? These iterator-like functions are not built into the language Just a programming pattern Though many languages have built-in support, which often allows stopping early without resorting to exceptions This pattern separates recursive traversal from data processing Can reuse same traversal for different data processing Can reuse same data processing for different data structures In both cases, using common vocabulary concisely communicates intent 18

Examples with fold These are useful and do not use private data fun f1 xs = fold((fn (x,y) => x+y), 0, xs) fun f2 xs = fold((fn (x,y) => x andalso y>=0), true, xs) These are useful and do use private data fun f3 (xs,hi,lo) = fold(fn (x,y) => x + (if y >= lo andalso y <= hi then 1 else 0)), 0, xs) fun f4 (g,xs) = fold(fn (x,y) => x andalso g y), true, xs) 19

Iterators made better Functions like map, filter, and fold are much more powerful thanks to closures and lexical scope Function passed in can use any private data in its environment Iterator doesn t even know the data is there or what type it has 20