The Role of the Study of Programming Languages in the Education of a Programmer Dan Friedman Indiana University.

Slides:



Advertisements
Similar presentations
Introduction to Recursion and Recursive Algorithms
Advertisements

Some non-recursive tricks. The Lambda expression. More on Let, Let*, apply and funcall.
SSA and CPS CS153: Compilers Greg Morrisett. Monadic Form vs CFGs Consider CFG available exp. analysis: statement gen's kill's x:=v 1 p v 2 x:=v 1 p v.
CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists Dan Grossman Winter 2013.
1 Scheme and Functional Programming Aaron Bloomfield CS 415 Fall 2005.
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.
Functional Programming. Pure Functional Programming Computation is largely performed by applying functions to values. The value of an expression depends.
Lambda Calculus and Lisp PZ03J. Lambda Calculus The lambda calculus is a model for functional programming like Turing machines are models for imperative.
Chapter 3 Functional Programming. Outline Introduction to functional programming Scheme: an untyped functional programming language.
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.
ISBN Chapter 3 Describing Syntax and Semantics.
CSE341: Programming Languages Lecture 6 Tail Recursion, Accumulators, Exceptions Dan Grossman Fall 2011.
Road Map Introduction to object oriented programming. Classes
Functional programming: LISP Originally developed for symbolic computing Main motivation: include recursion (see McCarthy biographical excerpt on web site).
מבוא מורחב - שיעור 2 1 Lecture 2 - Substitution Model (continued) - Recursion - Block structure and scope (if time permits)
1 Functional languages (e.g. Scheme, ML) Scheme is a functional language. Scheme is based on lambda calculus. lambda abstraction = function definition.
Functional programming: LISP Originally developed for symbolic computing First interactive, interpreted language Dynamic typing: values have types, variables.
Describing Syntax and Semantics
Recursion. Definitions I A recursive definition is a definition in which the thing being defined occurs as part of its own definition Example: A list.
CHAPTER 10 Recursion. 2 Recursive Thinking Recursion is a programming technique in which a method can call itself to solve a problem A recursive definition.
Programming Paradigms Imperative programming Functional programming Logic programming Event-driven programming Object-oriented programming A programming.
Chapter 7 Designing Classes. Class Design When we are developing a piece of software, we want to design the software We don’t want to just sit down and.
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
Cs7100(Prasad)L8Proc1 Procedures. cs7100(Prasad)L8Proc2 Primitive procedures  etc User-defined procedures –Naming a sequence of operations.
© Kenneth C. Louden, Chapter 11 - Functional Programming, Part III: Theory Programming Languages: Principles and Practice, 2nd Ed. Kenneth C. Louden.
מבוא מורחב 1 Review: scheme language things that make up scheme programs: self-evaluating 23, "hello", #t names +, pi combinations (+ 2 3) (* pi 4) special.
Chapter 13 Recursion. Learning Objectives Recursive void Functions – Tracing recursive calls – Infinite recursion, overflows Recursive Functions that.
ISBN Chapter 3 Describing Semantics -Attribute Grammars -Dynamic Semantics.
Functional Programming Universitatea Politehnica Bucuresti Adina Magda Florea
Dr. Philip Cannata 1 Functions and Recursion. Dr. Philip Cannata 2 10 Java (Object Oriented) ASP RDF (Horn Clause Deduction, Semantic Web) Relation Jython.
Objects & Dynamic Dispatch CSE 413 Autumn Plan We’ve learned a great deal about functional and object-oriented programming Now,  Look at semantics.
© Kenneth C. Louden, Chapter 11 - Functional Programming, Part III: Theory Programming Languages: Principles and Practice, 2nd Ed. Kenneth C. Louden.
Plt /17/ Environment-Passing Interpreters Programming Language Essentials 2nd edition Chapter 3.8 Parameter-Passing Variations.
Semantics In Text: Chapter 3.
0 Odds and Ends in Haskell: Folding, I/O, and Functors Adapted from material by Miran Lipovaca.
 Objects versus Class  Three main concepts of OOP ◦ Encapsulation ◦ Inheritance ◦ Polymorphism  Method ◦ Parameterized ◦ Value-Returning.
CMSC 330: Organization of Programming Languages Operational Semantics a.k.a. “WTF is Project 4, Part 3?”
CMSC 330: Organization of Programming Languages Operational Semantics.
Prof. Necula CS 164 Lecture 171 Operational Semantics of Cool ICOM 4029 Lecture 10.
Ada, Scheme, R Emory Wingard. Ada History Department of Defense in search of high level language around Requirements drafted for the language.
C H A P T E R E I G H T Functional Programming Programming Languages – Principles and Paradigms by Allen Tucker, Robert Noonan.
Operational Semantics of Scheme
Chapter 13 Recursion Copyright © 2016 Pearson, Inc. All rights reserved.
6.001 SICP Variations on a Scheme
CS 326 Programming Languages, Concepts and Implementation
The interpreter.
CS 326 Programming Languages, Concepts and Implementation
Case Study: Undefined Variables
Chap. 6 :: Control Flow Michael L. Scott.
The Metacircular Evaluator
Lecture 23 Pages : Separating Syntactic Analysis from Execution. We omit many details so you have to read the section in the book. The halting.
Dynamic Scoping Lazy Evaluation
The Metacircular Evaluator
Chap. 6 :: Control Flow Michael L. Scott.
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.
The Metacircular Evaluator (Continued)
6.001 SICP Further Variations on a Scheme
6.001 SICP Explicit-control evaluator
6.001 SICP Explicit-control evaluator
6.001 SICP Variations on a Scheme
Recursion Taken from notes by Dr. Neil Moore
Dan Grossman / Eric Mullen Autumn 2017
This Lecture Substitution model
6.001 SICP Interpretation Parts of an interpreter
topics interpreters meta-linguistic abstraction eval and apply
Recursive Procedures and Scopes
Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator
Defining Macros in Scheme
Presentation transcript:

The Role of the Study of Programming Languages in the Education of a Programmer Dan Friedman Indiana University

Why study programming languages? First: To teach one to avoid bad ideas –A little history about dynamic scope –A small discussion about types –Improper implementation of tail- calls 2

Second: To embrace good ideas in a representationally-independent fashion –Resolving tail-calls until something better comes along! 3 Why study programming languages?

Other roles: Three qoutes from students: –Jon Rossie: The life of a programming language expert in a world that does not know what one is and does not understand what one does... 4 Why study programming languages?

Every program is an interpreter! Programs are data All data are programs The hardware is an interpreter A compiler is an interpreter A type checker is an interpreter! 5

Data must be interpreted What is the interpretation of “5” What is the interpretation of “V” –A character? –A number? What is the interpretation of a function that takes “XIV” and produces XV”? –The successor function? –The predecessor function? 6

Essentials of Programming Languages Programmers like several PL Programmers are upset if things are difficult to do in their favorite PL Studying PL alleviates this problem Programmers are expected to learn PL But there are certain language design issues that are essential... 7

Other roles: Three quotes from students: –Anurag Mendhekar: I believe in the power of abstraction in software development... 8 Why study programming languages?

Separate what you want to do from how are you going to do it! Details are for later, after the ideas are developed and prototyped Details can be the implementation of the language design or of the language itself 9 Why study programming languages?

What do we mean by the study? The application of one’s mental faculties to the acquisition of knowledge in a particular field or to a specific subject One acquires such knowledge by developing a firm foundation of concepts to absorb knowledge Modeling the artifact one is studying 10

What do we mean by the study? For instance: knowing that a language passes its parameters by value is better than a description of what call-by-value is If one knows call-by-value -calculus one only needs to know what items in the language are values! 11

What do we mean by the study of programming languages? The semi-formal analysis of programming language concepts and their underlying principles that have lasted beyond a decade of their discovery! Syntax should not be the focus! 12

A programming languages concept: Lexical Scope Free variables are bound to values when procedures are created Around since Algol 60 Logicians have used it for much longer, as quantifiers  and  rely on lexical scope 13

Lexical Scope > let a = 3 in let p = proc (x) +(x, a) a = 5 in *(a, p(2))  *(5, +(2, 3)) = 25 14

( x E Tuple*)== (ormap( (x)E)Tuple*) ( x E Tuple*)== (andmap( (x)E)Tuple*) and 15   The power of -abstraction Relational database system operators (relying on lexical scope)

To teach one to avoid bad ideas –A little history about dynamic scope –A small discussion about types –Improper implementation of tail- calls 16 Why study programming languages?

Dynamic Scope > let a = 3 in let p = proc (x) +(x, a) a = 5 in *(a, p(2))  *(5, +(2, 5)) = 35 17

When you study scoping... You are likely to discover dynamic scope first You need to know why dynamic scope is a mistake! You need to know about the choice of a name for a bound variable 18

 -substitution ( (x) x) = ( (y) y) To change the x to y you need to use a name that is not used in the expression 19 = ( (y) ( (x)(y x))) ( (z) ( (x)(z x)))

(define map ( (f ls) (if (null? ls) ’ () (cons (f (first ls)) (map f (rest ls)))))) Consider the definition of map 20

What happens when  -rule works with map, with lexical scope? (let ((ls ’ ( ))) (map ( (x) (cons x ls)) ls)) > (( ) ( ) ( ) ( )) 21

What does this return if let and are dynamically scoped? It starts out the same: ( ( )... But, on the second recursion, ls gets smaller, so it affects the ls inside the definition of map ! Isn’t that a surprise? 22

Should any language designer be allowed to inflict such horrifying thoughts on a language user? >(( ) ( ) (3 3 4) (4 4)) 23

Equations for Lexical and Dynamic Binding =( (arg)( (env)E[M]env[x arg])) versus =( (arg)( (enw)E[M]env[x arg])) 24 E[( (x)M)]env  

To teach one to avoid bad ideas –A little history about dynamic scope –A small discussion about types –A disaster in the implementation of tail-calls 25 Why study programming languages?

What is wrong with this Scheme program? Nothing? 26 (if (= n 0) (+ n 5) (not (= (length ls) 4)))

Nothing? 27 How about this one? ((if (= n 0) 5 ( (x) (+ x 7))) 6)

What is wrong with this Scheme program? The value of the conditional is either a number or a boolean! 28 (if (= n 0) (+ n 5) (not (= (length ls) 4)))

The value of the conditional is either a number or a function! So, sometimes we will apply a function to a number, but other times we will apply the number five to a number! 29 How about this one? ((if (= n 0) 5 ( (x) (+ x 7))) 6)

To teach one to avoid bad ideas –A little history about dynamic scope –A small discussion about types –Improper implementation of tail- calls 30 Why study programming languages?

The problem Most implementations of Java and C do not handle tail-calls properly; the problem is not just recursive calls, but also method calls! Java does not encourage the writing of recursive programs But Java can be ok... assume that Scheme (Lisp) code can be easily converted to Java-code 31

The solution Use correctness-preserving transformations Transformations are simple and logical, Should be used when the opportunity arises Solve the problem of language implementation... for Java and C! 32

(define E ( (e r) (cases expression e (lit-exp (datum) datum) (var-exp (id) (r id)) (primapp-exp (prim rands) (prim (map ( (x) (E x r)) rands))) (if-exp (test-e true-e false-e) (if (E test-e r) (E true-e r) (E false-e r))) (proc-exp (ids body) ( (args) (E body ( (id) (if (memq id ids) (lookup id ids args) (r id)))))) (app-exp (rator rands) ((E rator r) (map ( (x) (E x r)) rands)))))) 33

DO NOT PANIC WHILE READING THE CODE THAT FOLLOWS DETAILS ARE FOR LATER 34

(define sum ( (n) (if (= n 0) 0 (+ n (sum (- n 1)))))) The call: > (sum ) sum program with a non-tail call 35 Nontail calls: embedded calls

(define sum ( (n acc ) (if (= n 0) acc (sum (- n 1)(+ n acc ))))) The call: > (sum ) 36 Implementation using an accumulator so that it would contain no non-tail calls. Programs in Tail form

The problem Running these programs in Java would not give the right answer: almost guaranteed! We are relying on a control stack, which is not very deep: Java assumes that most of your programs have a lot of while loops and assignment statements! The two Java programs for sum will produce the same wrong result: an exception! 37

Second: To embrace good ideas in a representationally-independent fashion –Resolving tail-calls until something better comes along! 38 Why study programming languages?

(define n) (define acc ) (define sum ( () (if (= n 0) acc {( acc (+ n acc)) ;; (begin(set! ( n (- n 1)) (sum)})))   39 Transforming the tail form into register form Substitute the call for assignment statements:

Transforming a Java program to make it work! > {( acc 0);assigment ( n ) (sum)} ;goto 40   The execution: 1. Set the registers 2. Make the call! But, In Java, this program still blows up!

Next: we transform the program into suspended-goto form ( define sum ( () (if (= n 0) acc {( acc (+ n acc )) ( n (- n 1)) ( ()(sum))} > {( acc 0) ( n ) ( ()(sum))} 41    

But( ()( f )) = f, in -calculus -rule restricted to variables: the -suspended-goto form. 42 (define sum ( () (if (= n 0) acc {( acc (+ n acc )) ( n (- n 1)) sum}))) > {( acc 0) ( n ) sum}      

Executing a program in suspended form In Java, we are required to use a while loop, which is primitive in Java and does not grow the stack We need to define a variable false instead of acc to terminate the while loop The accumulator is de-referenced at the end of the computation 43

44 (define sum ( () (if (= n 0) false {( acc (+ n acc )) ( n (- n 1)) sum})))   The new program

45 The control loop: (define run ( () {(while (sum) ’ no-op) acc })) The call: > {( acc 0) ( n ) (run)}   The new program

Independence of parameters We introduce a new register action to avoid reliance on the “return” facilities The value returned from sum is placed in action No reliance on arguments being passed nor the value being returned, leading to trampoline form 46

47 (define action ) (define sum ( () (if (= n 0) ( action false) {( acc (+ n acc )) ( n (- n 1)) ( action sum)})))     Independence of parameters

48 The control loop: (define run ( () {(while action ( action )) acc })) The call: > {( acc 0) ( n ) ( action sum) (run)}    Independence of parameters

Can every program be written in tail form? The two initial programs for sum (tail and non-tail forms) return the same result but compute differently; The first numbers added in the non-tail form were 1 and 0, but in the tail form, the first two numbers added were n and 0 (we relied on associative and commutative properties of sum) We cannot always do that! 49

Putting programs into tail form An interpreter can be put into tail-form (Essentials, Chap. 7) An interpreter can also be put into register form! But we need to transform any program to one that can be written and run in any host language 50

Putting programs into tail form There is an algorithm in: “Call-by-value, call-by-name and the lambda calculus” by Gordon Plotkin, Fate lent a hand: Amr Sabry and Matthias Felleisen discovered a new algorithm (Chapter 8, of the second edition of “Essentials...”) 51

Putting programs into tail form First, let’s transform the sum program into preregister-tail form without using the associative and commutative properties Then, transform the program into trampoline form This kind of code is said to be in continuation-passing style 52

The original sum program... again 53 ( (n) (if (= n 0) 0 (+ n (sum (- n 1)))))) The call: > (sum ) The program: (define sum

Continuations Programs passed as arguments to other programs indicating what to do next We need to add such an argument to every program that will be put into continuation- passing style This has to be done for every -expression of the original program ! 54

(define id ( ( acc ) acc )) (define sum ( (n cont ) ( cont (if (= n 0) 0 (+ n (sum (- n 1) id )))))) > (sum id ) The sum in continuation-passing style 55

( define sum ( (n cont ) (if (= n 0) ( cont 0) ( cont (+ n (sum (- n 1) id )))))) 56 The sum in continuation-passing style Let’s push the continuation through the branches of the if-expression: > (sum id ) The call:

(define sum ( (n cont ) (if (= n 0) ( cont 0) (sum (- n 1) ( ( acc ) ( cont (+ n acc ))))))) 57 The sum in continuation-passing style Let’s push the continuation through the embedded sum:

Continuations The program has been transformed into tail- form Next: we must dereference every free variable used in the continuation 58

The continuation with the free variables: ( ( acc ) ( cont (+ n acc ))) The two free variables are n and cont, so we replace the entire expression by (let ((n n)( cont cont )) ( ( acc ) ( cont (+ n acc )))) 59

(define sum ( (n cont ) (if (= n 0) ( cont 0) (sum (- n 1) (let ((n n)( cont cont )) ( ( acc ) ( cont (+ n acc )))))))) 60 The preregistered tail-form:

( ( acc ) acc ) or ( ( acc ) ( cont (+ n acc ))) 61 But we might be in a language that does not directly support higher-order functions such as: We can still use continuation-passing style, but we need to change the representation of continuations

Solution: Replace calls of the form (cont s) with ( apply-cont cont s): (define sum ( (n cont ) (if (= n 0) (apply-cont cont 0) (sum (- n 1) (let ((n n) ( cont cont )) ( ( acc ) (apply-cont cont (+ n acc ))) ))))) 62

Solution: Replace calls of the form (cont s) with (apply-cont cont s). (define apply-cont ( ( cont acc ) ( cont acc ))) 63 Where: With this, we come to the representation- independent-preregister-tail form, as follows:

(define id ’ ()) (define sum ( (n cont ) (if (= n 0) (apply-cont cont 0) (sum (- n 1) (cons n cont ))))) (define apply-cont ( ( cont acc ) (if (null? cont ) acc (apply-cont(cdr cont ) (+ (car cont ) acc ))))) > (sum id ) 64

Where are we? All calls are tail-calls The dereferencing of free variables happens automatically when cons is invoked So, we can proceed as we did in the tail form definitions of sum leading to the trampoline form, as follows: 65

(define sum ( () (if (= n 0) {( cont cont ) ( acc 0) ( action apply-cont)} {( cont (cons n cont )) ( n (- n 1)) ( action sum)})))       Trampoline form 66

(define apply-cont ( () (if (null? cont ) ( action false) {( acc (+ (car cont ) acc )) ( cont (cdr cont )) ( action apply-cont)}))) > {( cont id ) ( n ) ( action sum) (run)} 67       

Modeling the apply-cont dispatch Using the abstract method apply-cont by inheriting from the associated abstract class of continuation types (A Little Java, A Few Patterns, Chap. 1) There will be two subclasses –For continuation modeled by the empty list –For continuations modeled by cons 68

Continuations as procedures Alternatively, we can go back to the version of continuations represented as procedures We can treat those procedures as actions, as follows: 69

(define id ( () ( action false))) (define sum ( () (if (= n 0) {( acc 0) ( action cont ) } {( cont (let ((n n)( cont cont )) ( () {( acc (+ n acc )) ( action cont )}))) ( n (- n 1)) ( action sum)})))         70

The moral... A problem with poor implementation technology can be solved with good correctness-preserving transformations Our approach relies heavily on such transformations You will learn to develop your own perspective on how to implement things elegantly! 71

Other roles: Three quotes from students: –Jonathan Sobel: “That was the amazing part: I had produced a program that I could not have written, and in any case would not have wanted to write.” 72 Why study programming languages?

Conclusion The study of programming languages yields general-purpose tools that allow you to do things that are too hard to do without them. Learning these tools is the standard fare for researchers in programming languages 73

Conclusion A final quote from Christopher Strachey: –I always worked with programming languages because it seemed to me that until you could understand those, you really couldn’t understand computers. Understanding them doesn’t really mean only being able to use them. A lot of people can use them without understanding them. 74

For those who wish to run this code in Scheme instead of Java or C, here is the definition of while. (define-syntax while (syntax-rules () ((while exp stmts...) (let loop () (if exp (begin stmts...(loop))) )))) 75