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

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

The Environment Model. Nate Foster Spring 2018

The Environment Model

CS Lecture 7: The dynamic environment. Prof. Clarkson Spring Today s music: Down to Earth by Peter Gabriel from the WALL-E soundtrack

Typed Lambda Calculus. Chapter 9 Benjamin Pierce Types and Programming Languages

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

CS558 Programming Languages

CMSC 330: Organization of Programming Languages

CS558 Programming Languages

Recap: Functions as first-class values

CS558 Programming Languages. Winter 2013 Lecture 3

Topics Covered Thus Far CMSC 330: Organization of Programming Languages

Topics Covered Thus Far. CMSC 330: Organization of Programming Languages. Language Features Covered Thus Far. Programming Languages Revisited

Functional Programming. Pure Functional Programming

Types, Type Inference and Unification

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

Tail Calls. CMSC 330: Organization of Programming Languages. Tail Recursion. Tail Recursion (cont d) Names and Binding. Tail Recursion (cont d)

CS 360 Programming Languages Interpreters

Formal Semantics. Prof. Clarkson Fall Today s music: Down to Earth by Peter Gabriel from the WALL-E soundtrack

CMSC330. Objects, Functional Programming, and lambda calculus

CS 330 Lecture 18. Symbol table. C scope rules. Declarations. Chapter 5 Louden Outline

Compiler construction

Semantic Analysis. Lecture 9. February 7, 2018

Weeks 6&7: Procedures and Parameter Passing

So what does studying PL buy me?

Some Advanced ML Features

Chapter 11 :: Functional Languages

CSCE 314 Programming Languages. Type System

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

Introduction to ML. Mooly Sagiv. Cornell CS 3110 Data Structures and Functional Programming

CSE 341 : Programming Languages

Informal Semantics of Data. semantic specification names (identifiers) attributes binding declarations scope rules visibility

Control in Sequential Languages

The Substitution Model

The role of semantic analysis in a compiler

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

Type Inference. Prof. Clarkson Fall Today s music: Cool, Calm, and Collected by The Rolling Stones

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

CSE 341: Programming Languages

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

Lambda Calculus LC-1

Lambda Calculus. Gunnar Gotshalks LC-1

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

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

CS558 Programming Languages

G Programming Languages - Fall 2012

Variables and Bindings

Introduction to OCaml

Lectures Basics in Procedural Programming: Machinery

CMSC 330: Organization of Programming Languages. Operational Semantics

CSE 341 Section 5. Winter 2018

CMSC 330, Fall 2013, Practice Problem 3 Solutions

CSCI-GA Scripting Languages

CS558 Programming Languages

Comp 411 Principles of Programming Languages Lecture 7 Meta-interpreters. Corky Cartwright January 26, 2018

CMSC 330, Fall 2013, Practice Problems 3

CS558 Programming Languages

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

CVO103: Programming Languages. Lecture 5 Design and Implementation of PLs (1) Expressions

Introduction to ML. Mooly Sagiv. Cornell CS 3110 Data Structures and Functional Programming

COSE212: Programming Languages. Lecture 3 Functional Programming in OCaml

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

Lecture 15 CIS 341: COMPILERS

CSE 307: Principles of Programming Languages

CIS24 Project #3. Student Name: Chun Chung Cheung Course Section: SA Date: 4/28/2003 Professor: Kopec. Subject: Functional Programming Language (ML)

Compilers. Type checking. Yannis Smaragdakis, U. Athens (original slides by Sam

Types and Type Inference

CS 314 Principles of Programming Languages

Functional Languages. CSE 307 Principles of Programming Languages Stony Brook University

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

Lecture 13 CIS 341: COMPILERS

Programming Language Pragmatics

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

CMSC 330: Organization of Programming Languages. OCaml Imperative Programming

CS 242. Fundamentals. Reading: See last slide

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler so far

Introduction to ML. Mooly Sagiv. Cornell CS 3110 Data Structures and Functional Programming

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

The Substitution Model. Nate Foster Spring 2018

Programmiersprachen (Programming Languages)

OCaml Data CMSC 330: Organization of Programming Languages. User Defined Types. Variation: Shapes in Java

G Programming Languages Spring 2010 Lecture 4. Robert Grimm, New York University

Syntax Errors; Static Semantics

Static Semantics. Lecture 15. (Notes by P. N. Hilfinger and R. Bodik) 2/29/08 Prof. Hilfinger, CS164 Lecture 15 1

1. true / false By a compiler we mean a program that translates to code that will run natively on some machine.

CS-XXX: Graduate Programming Languages. Lecture 22 Class-Based Object-Oriented Programming. Dan Grossman 2012

Types and Type Inference

Functional Programming. Pure Functional Languages

CMSC 330: Organization of Programming Languages. OCaml Imperative Programming

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

CMSC330 Fall 2013 Practice Problems 6 Solutions

Programming Languages Third Edition. Chapter 10 Control II Procedures and Environments

4/19/2018. Chapter 11 :: Functional Languages

CMSC 330: Organization of Programming Languages. Formal Semantics of a Prog. Lang. Specifying Syntax, Semantics

Scope, Functions, and Storage Management

CS-XXX: Graduate Programming Languages. Lecture 9 Simply Typed Lambda Calculus. Dan Grossman 2012

G Programming Languages - Fall 2012

Robot Programming with Lisp

Lambda Calculus and Lambda notation in Lisp II. Based on Prof. Gotshalks notes on Lambda Calculus and Chapter 9 in Wilensky.

G Programming Languages - Fall 2012

Transcription:

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

t ::= x x. t t t Call-by-value big-step Operational Semantics terms variable v ::= values abstraction x. t abstraction values application other values x. t x. t (V-Value) t 1 x. t 3 t 2 v 1 [x v 1 ] t 3 v 2 t 1 t 2 v 2 (V-App)

A Pseudocode for call-by value interpreter Lambda eval(lambda t) { switch(t) { case t= x. t1: // A value return t case t = t1 t2: Lambda temp = eval(t1); assert temp = x. t3; Lambda v1 = eval(t2) ; // v1 must be a value return eval([x v1] t3) ; default: assert false; } }

Formal Semantics of Functional Programs Compile into typed lambda calculus Small step operational semantics Environment Expression Environment Expression

Essential OCcaml sublanguage e ::= c x (e 1,, e n ) e 1 e 2 fun x -> e let x = e 1 in e 2 match e 0 with p i -> e i

Evaluation of Expression Expressions evaluate to values in a dynamic environment env :: e - - > v Evaluation is meaningless if expression does not type check Values are a syntactic subset of expressions: v ::= c (v 1,, v n ) fun x -> e

Dealing with Functions as Values Anonymous functions fun x-> e are values env :: (fun x -> e) --> (fun x -> e)

Evaluating let expressions To evaluate let x = e 1 in e 2 in environment env: 1. Evaluate the binding expression e 1 to a value v 1 in environment env env :: e 1 --> v 2. Extend the environment to bind x to v 1 env = env [x v 1 ] (newer bindings temporarily shadow older bindings) 3. Evaluate the body expression e 2 to a value v 2 in environment env env :: e 2 --> v 2 4. Return v 2

Evaluating Function Application take 1 To evaluate e 1 e 2 in environment env 1. Evaluate e 2 to a value v 2 in environment env env :: e 2 --> v 2 Note: right to left order, like tuples, which matters in the presence of side effects 2. Evaluate e 1 to a value v 1 in environment env env :: e 1 --> v 1 Note that v 1 must be a function value fun x -> e 3. Extend environment to bind formal parameter x to actual value v 2 env = env [x v 2 ] 4. Evaluate body e to a value v in environment env env :: e --> v 5. Return v

Evaluating Function Application take 1 if env :: e2 --> v2 and env :: e1 --> (fun x -> e) and env[x v2] :: e --> v then env :: e1 e2 --> v

Evaluating Function Application Simple Example let f = fun x -> x in f 0 env 0 =[] 1. Evaluate binding expression fun x->x to a value in empty environment env 0 2. Extend environment to bind f to fun x->x env 1 =env 0 [f fun x -> x ] = [f fun x -> x] 3. Evaluate let-body expression f 0 in environment env 1 env 1 :: f 0 --> v1 1. Evaluate 0 to a value 0 in environment env 1 2. Evaluate f to fun x -> x 3. Extend environment to bind formal parameter x to actual value 0 env 2 = env 1 [x 0] = [f, x 0] 4. Evaluate the function body x in environment env 2 env 2 :: x--> 0 4. Return 0 env 2 :: x--> 0

Hard Example let x = 1 in let f = fun y -> x in let x = 2 in f 0 1. What is the result of the expression? 2. What does OCaml say? 3. What do you say?

Hard Example Ocaml let x = 1 in let f = fun y -> x in let x = 2 in f 0 warning 26: x unused variable :- int 1

Hard Example C } } int x = 1 { int f(int y) { return x ; } { int x = 2; printf( %d, f(0)) ; }

Why different answers? Two different rules for variable scope Rule of dynamic scope (lisp) Rule of lexical (static) scope (Ocaml, Javascript, Scheme, )

Dynamic Scope Rule of dynamic scope: The body of a function is evaluated in the current dynamic environment at the time the function is called, not the old dynamic environment that existed at the time the function was defined Use latest binding of x Thus return 2

Lexical Scope Rule of lexical scope: The body of a function is evaluated in the old dynamic environment that existed at the time the function was defined, not the current environment when the function is called Causes OCaml to use earlier binding of x Thus return 1

Scope Rule of dynamic scope: The body of a function is evaluated in the current dynamic environment at the time the function is called, not the old dynamic environment that existed at the time the function was defined Rule of lexical scope: The body of a function is evaluated in the old dynamic environment that existed at the time the function was defined, not the current environment when the function is called In both, environment is extended to map formal parameter to actual value Why would you want one vs. the other?

Lexical vs. dynamic scope Consensus after decades of programming language design is that lexical scope is the right choice Dynamic scope is convenient in some situations Some languages use it as the norm (e.g., Emacs LISP, LaTeX) Some languages have special ways to do it (e.g., Perl, Racket) But most languages just don t have it

Why Lexical Scope (1) Programmer can freely change names of local variables (* 1 *) let x = 1 (* 2 *) let f y = let x = y + 1 in fun z -> x+y+z (* 3 *) let x = 3 (* 4 *) let w = (f 4) 6 (* 1 *) let x = 0 (* 2 *) let f y = let q = y + 1 in fun z -> q+y+z (* 3 *) let x = 3 (* 4 *) let w = (f 4) 6

Why Lexical Scope (2) Type checker can prevent run-time errors (* 1 *) let x = 1 (* 2 *) let f y = let x = y + 1 in fun z -> x+y+z (* 3 *) let x = 3 (* 4 *) let w = (f 4) 6 (* 1 *) let x = 0 (* 2 *) let f y = let x = y + 1 in fun z -> x+y+z (* 3 *) let x = hi (* 4 *) let w = (f 4) 6

Exception Handling Resembles dynamic scope: raise e transfers control to the most recent exception handler like how dynamic scope uses most recent binding of variable

Where is an exception caught? Dynamic scoping of handlers Throw to most recent catch on run-time stack Dynamic scoping is not an accident User knows how to handler error Author of library function does not

Implementing time travel (lexical) Q How can functions be evaluated in old environments? A The language implementation keeps them around as necessary A function value is really a data structure that has two parts: 1. The code 2. The environment that was current when the function was defined 1. Gives meaning to all the free variables of the function body Like a pair But you cannot access the pieces, or directly write one down in the language syntax All you can do is call it This data structure is called a function closure A function application: evaluates the code part of the closure in the environment part of the closure extended to bind the function argument

Hard Example Revisited [1] let x = 1 in [2] let f = fun y -> x in [3] let x = 2 in [4] let z = f 0 in z With lexical scope: Line 2 creates a closure and binds f to it: Code: fun y -> x Environment: [x 1] Line 4 calls that closure with 0 as argument In function body, y maps to 0 and x maps to 1 So z is bound to 1

Another Example [1] let x = 1 in [2] let f y = x + y in [3] let x = 3 in [4] let y = 4 in [5] let z = f (x + y) in z With dynamic scope: 1. Creates a closure and binds f to it: Code: fun y -> x + y Environment: [x 1] 2. Line 5 env =[x 3, y 4] 3. Line 5 calls that closure with x+y=7 as argument In function body, x maps to 1 So z is bound to 8

Another Example [1] let x = 1 in [2] let f y = x + y in [3] let x = 3 in [4] let y = 4 in [5] let z = f (x + y) in z With dynamic scope: 1. Line 5 env =[x 3, y 4] 2. Line 5 calls that closure with x+y=7 as argument In function body, x maps to 3, so x+y maps to 10 Note that argument y shadows y from line 4 So z is bound to 10

Closure Notation <<code, environment>> <<fun y -> x+y, [x 1>> With lexical scoping, well-typed programs are guaranteed never to have any variables in the code body other than function argument and variables bound by closure environment

Evaluating Function Application take 2 To evaluate e 1 e 2 in environment env 1. Evaluate e 2 to a value v 2 in environment env env :: e 2 --> v 2 Note: right to left order, like tuples, which matters in the presence of side effects 2. Evaluate e 1 to a value v 1 in environment env env :: e 1 --> v 1 Note that v 1 must be a closure with function value fun x -> e and environment env 3. Extend environment to bind formal parameter x to actual value v 2 env = env [x v 2 ] 4. Evaluate body e to a value v in environment env env :: e --> v 5. Return v

Evaluating Function Application take 2 if env :: e2 --> v2 and env :: e1 --> <<fun x -> e, env >> and env [x v2] :: e --> v then env :: e1 e2 --> v

Evaluating Anonymous Function Application take 2 Anonymous functions fun x-> e are closures env :: (fun x -> e) --> <<fun x -> e, env>>

Why are Closure useful? Hides states in an elegant way Useful for Implementing objects Web programming Operated system programming Emulating control flow

Simple Example let startat x = let incrementby y = x + y in incrementby val startat : int -> int -> int = <fun> let closure1 = startat 3 val closure1 : int -> int = <fun> let closure2 = startat 5 val closure2 : int -> int = <fun> closure1 7 :- int =10 closure2 9 :- int =14

Another Example let derivative f dx = fun x -> f (x + dx) f x / dx val derivative : (int -> int) -> int -> int -> int = <fun>

Implementation Notes Duration of closure can be long Usually implemented with garbage collection It is possible to support lexical scopes without closure (using stack) if one of the following is forbidden: Nested scopes (C, Java) Returning a function (Algol, Pascal)

Essential OCcaml sublanguage e ::= c x e 1 e 2 fun x -> e let x = e 1 in e 2 match e 0 with p i -> e i

Essential OCcaml sublanguage+rec e ::= c x (e 1,, e n ) e 1 e 2 fun x -> e let x = e 1 in e 2 match e 0 with p i -> e i let rec f x = e1 in e2

let rec Evaluation How to handle let rec f x = e 1 in e 2

let rec Evaluation To evaluate let rec f x = e 1 in e 2 in environment env don t evaluate the binding expression e 1 1. Extend the environment to bind f to a recursive closure env = env [f <<f, fun x -> e 1, env>>] 2. Evaluate the body expression e 2 to a value v 2 in environment env env :: e 2 --> v 2 3. Return v 2

Closure in OCaml Closure conversion is an important phase of compiling many functional languages Expands on ideas we ve seen here Many optimizations possible Especially, better handling of recursive functions

Closures in Java Nested classes can simulate closures Used everywhere for Swing GUI! http://docs.oracle.com/javase/tutorial/uiswing/events/ generalrules.html#innerclasses Java 8 adds higher-order functions and closures Can even think of OCaml closures as resembling Java objects: closure has a single method, the code part, that can be Invoked closure has many fields, the environment part, that can be accessed

Closures in C In C, a function pointer is just a code pointer, period, No environment To simulate closures, a common idiom: Define function pointers to take an extra, explicit environment argument But without generics, no good choice for type of list elements or the environment Use void* and various type casts From Linux kernel: http://lxr.free-electrons.com/source/include/linux/kthread.h#l13

Summary Lexical scoping is natural Permit general programming style Works well with higher order functions Well understood Implemented with closures But requires long lived objects Integrated into many programming languages Some surprises (javascript)

Summary (Ocaml) Functional programs provide concise coding Compiled code compares with C code Successfully used in some commercial applications F#, ERLANG, Jane Street Ideas used in imperative programs Good conceptual tool Less popular than imperative programs