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

Slides:



Advertisements
Similar presentations
Some non-recursive tricks. The Lambda expression. More on Let, Let*, apply and funcall.
Advertisements

COP4020 Programming Languages Names, Scopes, and Bindings Prof. Xin Yuan.
Scheme in Scheme. Why implement Scheme in Scheme  Implementing a language is a good way to learn more about programming languages  Interpreters are.
1 Programming Languages (CS 550) Lecture Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
Getting started with ML ML is a functional programming language. ML is statically typed: The types of literals, values, expressions and functions in a.
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.
Cs784(TK)1 Semantics of Procedures and Scopes. Kinds of Scope Static or Lexical scope –determined by structure of program –Scheme, C++, Java, and many.
1 Scheme Scheme is a functional language. Scheme is based on lambda calculus. lambda abstraction = function definition In Scheme, a function is defined.
Functional programming: LISP Originally developed for symbolic computing Main motivation: include recursion (see McCarthy biographical excerpt on web site).
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:
How to load a program file? Lisp programs in Allegro are saved under the file extension.cl. To load a file into the Lisp console, use the following: (load.
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.
1 Run time vs. Compile time The compiler must generate code to handle issues that arise at run time Representation of various data types Procedure linkage.
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.
EOPL3: Section 3.3 PROC and App B: SLLGEN
Chapter TwelveModern Programming Languages1 Memory Locations For Variables.
Chapter 7: Runtime Environment –Run time memory organization. We need to use memory to store: –code –static data (global variables) –dynamic data objects.
Functional Programing Referencing material from Programming Language Pragmatics – Third Edition – by Michael L. Scott Andy Balaam (Youtube.com/user/ajbalaam)
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
CS 326 Programming Languages, Concepts and Implementation Instructor: Mircea Nicolescu Lecture 7.
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,
Interpretation Environments and Evaluation. CS 354 Spring Translation Stages Lexical analysis (scanning) Parsing –Recognizing –Building parse tree.
CPS120: Introduction to Computer Science Decision Making in Programs.
The Loop Macro Many of the CL “functions” are actually macros (let, progn, if, etc) The most complicated macro in CL is probably the Loop macro –The Loop.
Functional Programming in Scheme and Lisp.
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.
Variables, Environments and Closures. Overview Touch on the notions of variable extent and scope Introduce the notions of lexical scope and dynamic.
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.
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.
1 CSC 222: Computer Programming II Spring 2004 Stacks and recursion  stack ADT  push, pop, top, empty, size  vector-based implementation, library 
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.
CS314 – Section 5 Recitation 9
Advanced Programming in C
Operational Semantics of Scheme
Functional Programming
Edited by Original material by Eric Grimson
6.001 SICP Object Oriented Programming
Variables, Environments and Closures
Names.
Names, Scopes, and Bindings: Scopes
Variables, Environments and Closures
Dynamic Scoping Lazy Evaluation
The Metacircular Evaluator
Scoping and Binding of Variables
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
Lisp and Scheme I.
Lecture 13 - Assignment and the environments model Chapter 3
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 We will 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.

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 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 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 (let [(pi ) (e )] (big-number? (expt pi e))) ((lambda (pi e) (big-number? (expt pi e))) ) and this is how we did it back before ~1973

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 is to 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 a statically scoped language, free variables in functions are looked up in the environment in which the function is defined In a dynamically scoped language, 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 and Emacs Lisp among themLogoEmacs Lisp 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) *SPEC* > (defun check-spe () *spe*) CHECK-SPEC > (check-spec) 5 > (let ((*spe* 6)) (check-spe)) 6

Advantages and 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

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) ???

> (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

> (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)) …)

> (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

> (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 Write a fancier make-counter function that 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) Different Scheme dialects have introduced different ways to mix positional arguments, optional argu- ments, default values, keyword argument, etc.

Closure tricks We can write several functions that are closed in the same environment, which can then 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"

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