Variables, Environments and Closures. Overview Touch on the notions of variable extent and scope Introduce the notions of lexical scope and dynamic.

Slides:



Advertisements
Similar presentations
Type Checking, Inference, & Elaboration CS153: Compilers Greg Morrisett.
Advertisements

Scheme in Scheme. Why implement Scheme in Scheme  Implementing a language is a good way to learn more about programming languages  Interpreters are.
Variables, Environments and Closures. Overview We will Touch on the notions of variable extent and scope Introduce the notions of lexical scope and.
Recap 1.Programmer enters expression 2.ML checks if expression is “well-typed” Using a precise set of rules, ML tries to find a unique type for the expression.
1 Programming Languages (CS 550) Lecture Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
Functional Programming. Pure Functional Programming Computation is largely performed by applying functions to values. The value of an expression depends.
CS 355 – PROGRAMMING LANGUAGES Dr. X. Apply-to-all A functional form that takes a single function as a parameter and yields a list of values obtained.
6.001 SICP SICP – October environment Trevor Darrell 32-D512 Office Hour: W web page:
Functional programming: LISP Originally developed for symbolic computing Main motivation: include recursion (see McCarthy biographical excerpt on web site).
Chapter 15 Functional Programming Languages. Copyright © 2007 Addison-Wesley. All rights reserved. 1–2 Introduction Design of imperative languages is.
Run time vs. Compile time
The environment of the computation Declarations introduce names that denote entities. At execution-time, entities are bound to values or to locations:
1 Scheme Although Scheme is syntactically a simple language, it supports sophisticated modeling: higher-order functions are a powerful tool in describing.
Functional programming: LISP Originally developed for symbolic computing First interactive, interpreted language Dynamic typing: values have types, variables.
CSC321: Programming Languages Names Chapter 4: Names 4.1 Syntactic Issues 4.2 Variables 4.3 Scope 4.4 Symbol Table 4.5 Resolving References 4.6 Dynamic.
Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 4 Names The first step toward wisdom is calling.
Introduction Even though the syntax of Scheme is simple, it can be very difficult to determine the semantics of an expression. Hacker’s approach: Run it.
Catriel Beeri Pls/Winter 2004/5 environment 19 II. Frames and frame structures Frame – set of bindings generated together in a binding generation event.
Chapter 7: Runtime Environment –Run time memory organization. We need to use memory to store: –code –static data (global variables) –dynamic data objects.
CS 355 – PROGRAMMING LANGUAGES Dr. X. Copyright © 2012 Addison-Wesley. All rights reserved.1-2 Topics Scope Scope and Lifetime Referencing Environments.
Functional Programming Universitatea Politehnica Bucuresti Adina Magda Florea
Functional Programming in Scheme and Lisp. Overview In a functional programming language, functions are first class objects. You can create them, put.
1 Names, Scopes and Bindings Aaron Bloomfield CS 415 Fall
10/16/2015IT 3271 All about binding n Variables are bound (dynamically) to values n values must be stored somewhere in the memory. Memory Locations for.
Functional Programming and Lisp. Overview In a functional programming language, functions are first class objects. In a functional programming language,
COMPILERS Symbol Tables hussein suleman uct csc3003s 2007.
Interpretation Environments and Evaluation. CS 354 Spring Translation Stages Lexical analysis (scanning) Parsing –Recognizing –Building parse tree.
Functional Programming in Scheme and Lisp.
Objects & Dynamic Dispatch CSE 413 Autumn Plan We’ve learned a great deal about functional and object-oriented programming Now,  Look at semantics.
1 The Evaluator. 2 Compiler vs. Interpreter Command Processing Unit The Computer Program in Low Level Machine Language Program in High Level Language.
SCHEME Scheme is elegant, clear, small, and powerful programming language. It is a dialect of LISP and can be classified as a semi-functional programming.
PRACTICAL COMMON LISP Peter Seibel 1.
CSE (c) S. Tanimoto, 2002 AI Techniques 1 Where and When Do Symbols Refer to Values and Functions? Scope and Extent of Bindings Bindings Scope Extent.
Milos Hauskrecht (PDF) Hieu D. Vu (PPT) LISP PROGARMMING LANGUAGE.
Concepts of programming languages Chapter 5 Names, Bindings, and Scopes Lec. 12 Lecturer: Dr. Emad Nabil 1-1.
1 Lecture 14: Assignment and the Environment Model (EM)
Fall 2008Programming Development Techniques 1 Topic 17 Assignment, Local State, and the Environment Model of Evaluation Section 3.1 & 3.2.
CSE 130 : Spring 2011 Programming Languages Ranjit Jhala UC San Diego Lecture 5: Functions and Closures.
Scheme in Scheme 2. What’s next  Adding set!  Dynamic vs. lexical variable scope  Extending mcscheme v1 with libraries  Can mcscheme execute mcscheme?
Procedure Definitions and Semantics Procedures support control abstraction in programming languages. In most programming languages, a procedure is defined.
Lambda Functions & Closures A Sydney PHP Group Presentation 2 nd October 2008 By Timothy Chandler.
CS314 – Section 5 Recitation 9
Operational Semantics of Scheme
Functional Programming
Edited by Original material by Eric Grimson
Variables, Environments and Closures
September 4, 1997 Programming Languages (CS 550) Lecture 6 Summary Operational Semantics of Scheme using Substitution Jeremy R. Johnson TexPoint fonts.
Env. Model Implementation
Names, Scopes, and Bindings: Scopes
Variables, Environments and Closures
Dynamic Scoping Lazy Evaluation
The Metacircular Evaluator
Closure Closure binds a first-class function and a lexical environment together This is a complex topic, so we will build up our understanding of it we.
Procedures App B: SLLGEN 1.
6.001 SICP Environment model
Bindings, Scope, and Extent
6.001 SICP Further Variations on a Scheme
Explicit Application of Procedures, and Explicit Evaluation
Homework Any Questions?.
Lecture 13 - Assignment and the environments model Chapter 3
6.001 SICP Environment model
6.001 SICP Variations on a Scheme
Peter Seibel Practical Common Lisp Peter Seibel
Bindings, Scope, and Extent
6.001 SICP Environment model
CSE 341 Lecture 11 b closures; scoping rules
Bindings, Scope, and Extent
topics interpreters meta-linguistic abstraction eval and apply
Lecture 6: Names (Revised based on the Tucker’s slides) 5/27/2019
More Scheme CS 331.
Presentation transcript:

Variables, Environments and Closures

Overview Touch on the notions of variable extent and scope Introduce the notions of lexical scope and dynamic scope for variables Provide a simple model for variable environments in Scheme Show examples of closures in Scheme

Variables, free and bound In this function, to what does the variable GOOGOL refer? (define (big-number? x) ;; returns true if x is a really big number (> x GOOGOL)) The scope of the variable X is just the body of the function for which it’s a parameter.scope

Here, GOOGOL is a global variable > (define GOOGOL (expt )) > GOOGOL > (define (big-number? x) (> x GOOGOL)) > (big-number? (add1 (expt ))) #t

Which X is accessed at the end? > (define GOOGOL (expt )) > GOOGOL > (define x -1) > (define (big-number? x) (> x GOOGOL)) > (big-number? (add1 (expt ))) #t

Variables, free and bound In the body of this function, we say that the variable (or symbol) X is bound and GOOGOL is freebound free (define (big-number? x) ; returns true if X is a really big number (> X GOOGOL)) If it has a value, it has to be bound somewhere else

The let form creates local variables > (let [ (pi ) (e ) ] (big-number? (expt pi e))) #f The general form is (let. ) It creates a local environment, binding the variables to their initial values, and evaluates the expressions in Returning the value of the last body expression Note: square brackets are like parens, but only match other square brackets. They can to help you cope with paren fatigue.

Let creates a block of expressions (if (> a b) (let ( ) (printf "a is bigger than b.~n") (printf "b is smaller than a.~n") #t) #f)

Let is just syntactic sugar for lambda These two are equivalent (let [(pi ) (e )] (big-number? (expt pi e))) ((lambda (pi e) (big-number? (expt pi e))) ) In the 2 nd, the lambda exp returns a function which is then applied to the two arguments

Let is just syntactic sugar for lambda What happens here: (define x 2) (let [ (x 10) (xx (* x 2)) ] (printf "x is ~s and xx is ~s.~n" x xx)) x is 10 and xx is 4.

Let is just syntactic sugar for lambda What happens here: (define x 2) ( (lambda (x xx) (printf "x is ~s and xx is ~s.~n" x xx)) 10 (* 2 x)) x is 10 and xx is 4.

Let is just syntactic sugar for lambda What happens here: (define x 2) (define (f x xx) (printf "x is ~s and xx is ~s.~n" x xx)) (f (* 2 x)) x is 10 and xx is 4.

let and let* The let special form evaluates all initial value expressions, and then creates a new environ- ment with local variables bound to them, “in parallel” The let* form does is sequentially let* expands to a series of nested lets (let* [(x 100)(xx (* 2 x))] (foo x xx) ) (let [(x 100)] (let [(xx (* 2 x))] (foo x xx) ) )

What happens here? > (define X 10) > (let [(X (* X X))] (printf "X is ~s.~n" X) (set! X 1000) (printf "X is ~s.~n" X) -1 ) ??? > X ???

What happens here? > (define X 10) > (let [(X (* X X))] (printf “X is ~s\n” X) (set! X 1000) (printf “X is ~s\n” X) -1 ) X is 100 X is 1000 > X 10

What happens here? > (define GOOGOL (expt )) > (define (big-number? x) (> x GOOGOL)) > (let [(GOOGOL (expt ))] (big-number? (add1 (expt )))) ???

What happens here? > (define GOOGOL (expt )) > (define (big-number? x) (> x GOOGOL)) > (let [(GOOGOL (expt ))] (big-number? (add1 (expt )))) #t The free variable GOOGOL is looked up in the environment in which the big-number? function was defined! Not in the environment in which it was called

functions Note that a simple notion of a function can give us the machinery for – Creating a block of code with a sequence of expressions to be evaluated in order – Creating a block of code with one or more local variables Functional programming language use functions to provide other familiar constructs (e.g., objects) And also constructs that are unfamiliar

Dynamic vs. Static Scoping Programming languages either use dynamic or static (aka lexical) scopingscoping In statically scoped languages, free variables in functions are looked up in the environment in which the function is defined In dynamically scoped languages, free variables are looked up in the environment in which the function is called

History Lisp started out as a dynamically scoped language and moved to static scoping with Common Lisp in ~1980 Common Lisp Today, fewer languages use only dynnamic scoping, Logo, Emacs Lisp, and unix shell scripting languages (e.g., bash) among themLogoEmacs Lispbash Perl and Common Lisp let you define some variables as dynamically scoped

Dynamic scoping Here’s a model for dynamic binding: Variables have a global stack of bindings Creating a new variable X in a block pushes a binding onto the global X stack Exiting the block pops X's binding stack Accessing X always produces the top binding

Special variables in Lisp Common Lisp's dynamically scoped variables are called special variables Declare a variable special using defvar > (set 'reg 5) 5 > (defun check-reg () reg) CHECK-REG > (check-reg) 5 > (let ((reg 6)) (check-reg)) 5 > (defvar *spe* 5) *SPE* > (defun check-spe () *spe*) CHECK-SPEC > (check-spec) 5 > (let ((*spe* 6)) (check-spe)) 6

Dynamic advantages/disadvantages + Easy to implement + Easy to modify a function’s behavior by dynamically rebinding free variables (let ((IO stderr)) (printf “warning…”)) - Can unintentionally shadow a global variable - A compiler can never know what a free variable will refer to, making type checking impossible

Closures Lisp is a lexically scoped language Free variables referenced in a function those are looked up in the environment in which the function is defined Free variables are those a function (or block) doesn’t create scope for A closure is a function that remembers the environment in which it was createdclosure An environment is just a collection of variable names and their values, plus a parent environment

Why closures, where closures Closures turn out to be very useful in languages that support functional programming Most modern dynamic PLs do: Python, Javascript, Php, Ruby, etc. They are interesting when you can (1) define a function in an environment, (2) return a reference to it outside the environment and (3) call the function later

Example: make-counter make-counter creates an environment using let with a local variable C initially 0 It defines and returns a new function, using lambda, that can access & modify C > (define (make-counter) (let ((C 0)) (lambda () (set! C (+ 1 C)) C))) > (define c1 (make-counter)) > (define c2 (make-counter)) > (c1) 1 > (c1) 2 > (c1) 3 > (c2) ???

What is a function? (define (add1 x) (+ x 1)) This binds the variable add1 to a new function In Scheme, a function is just a data structure with three components: – A parameter list (e.g., (x)) – An body expression to evaluate (e.g., (+ x 1)) – A pointer to the variable environment it was created in

What’s an environment? An environment is a data structure with two parts: – A pointer to its parent environment, which might be null if this environment is the top-level global one – A data structure to hold pairs of variable names and their current values (e.g., a dictionary, hashtable, list of two-tuples) Operations on an environment include define, set! and lookup

Environment Operations There are just three basic operations on an environment Define: add a new variable in an environment and give it an initial value Lookup: find a variable in an enviroment or one of its ancestors and return its value Set!: find a variable in an environment or one of its ancestors and change its value

> (define C 100) > (define (mc) (let ((C 0)) (lambda () (set! C (+ C 1)) C))) > (define c1 (mc)) > (define c2 (mc)) > (c1) 1 > (c2) 1 global env null

> (define C 100) > (define (mc) (let ((C 0)) (lambda () (set! C (+ C 1)) C))) > (define c1 (mc)) > (define c2 (mc)) > (c1) 1 > (c2) 1 global env null 100 Table represents an environment as rows of variable names and pointers to their values

> (define C 100) > (define (mc) (let ((C 0)) (lambda () (set! C (+ C 1)) C))) > (define c1 (mc)) > (define c2 (mc)) > (c1) 1 > (c2) 1 global env null 100 ( ) (let ((C 0)) …) A structure with the three components of a function: parameter list, body and environment

Local environment created when mc was called with local var C > (define C 100) > (define (mc) (let ((C 0)) (lambda () (set! C (+ C 1)) C))) > (define c1 (mc)) > (define c2 (mc)) > (c1) 1 > (c2) 1 global env null 100 ( ) ((let ((C 0)) …)) ( ) ((set! C (+ C 1)) C ) 0 Function created by the lambda expr evaled in call to mc

> (define C 100) > (define (mc) (let ((C 0)) (lambda () (set! C (+ C 1)) C))) > (define c1 (mc)) > (define c2 (mc)) > (c1) 1 > (c2) 1 global env null 100 ( ) ((let ((C 0)) …)) ( ) ((set! C (+ C 1)) C ) 0 ( ) ((set! C (+ C 1)) C ) 0

> (define C 100) > (define (mc) (let ((C 0)) (lambda () (set! C (+ C 1)) C))) > (define c1 (mc)) > (define c2 (mc)) > (c1) 1 > (c2) 1 global env null 100 ( ) ((let ((C 0)) …)) ( ) ((set! C (+ C 1)) C ) 1 ( ) ((set! C (+ C 1)) C ) 0

> (define C 100) > (define (mc) (let ((C 0)) (lambda () (set! C (+ C 1)) C))) > (define c1 (mc)) > (define c2 (mc)) > (c1) 1 > (c2) 1 global env null 100 ( ) ((let ((C 0)) …)) ( ) ((set! C (+ C 1)) C ) 1 ( ) ((set! C (+ C 1)) C ) 1

A fancier make-counter This make-counter function takes an optional argument that specifies the increment > (define by1 (make-counter)) > (define by2 (make-counter 2)) > (define decrement (make-counter -1)) > (by2) 2 (by2) 4

Optional arguments in Scheme > (define (f (x 10) (y 20)) (printf "x=~a and y=~a\n" x y)) > (f) x=10 and y=20 > (f -1) x=-1 and y=20 > (f -1 -2) x=-1 and y=-2

Fancier make-counter (define (make-counter (inc 1)) (let ((C 0)) (lambda ( ) (set! C (+ C inc)))))

Keyword arguments in Scheme Scheme, like Lisp, also has a way to define functions that take keyword arguments – (make-counter) – (make-counter :initial 100) – (make-counter :increment -1) – (make-counter :initial 10 :increment -2) Scheme dialects have introduced different ways to mix positional arguments, optional arguments, default values, keyword argument, etc.

Closure tricks We can write several functions that are closed in the same environment, which can provide a private communication channel (define foo #f) (define bar #f) (let ((secret-msg "none")) (set! foo (lambda (msg) (set! secret-msg msg))) (set! bar (lambda () secret-msg))) (display (bar)) ; prints "none" (newline) (foo " attack at dawn") (display (bar)) ; prints ”attack at dawn"

Closures are powerful Closures let do many interesting and useful things, including – Delay a computation and execute it later – Implement streams – Curry functions – Etc. We’ll look at some of these next

Summary Scheme, like most modern languages, is lexically scoped Common Lisp is by default, but still allows some variables to be declared to be dynamically scoped A few languages still use dynamic scoping Lexical scoping supports functional program- ming & powerful mechanisms (e.g., closures) More complex to implement, though