CS2135 Lectures on Script Position. Recap: CGI scripts In the CGI protocol, there is no way to send the result of a script back to the page that invoked.

Slides:



Advertisements
Similar presentations
Higher-Order Functions and Loops c. Kathi Fisler,
Advertisements

Tail Recursion. Problems with Recursion Recursion is generally favored over iteration in Scheme and many other languages – It’s elegant, minimal, can.
1 Programming Languages (CS 550) Lecture Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
Introduction to PHP MIS 3501, Fall 2014 Jeremy Shafer
CS0004: Introduction to Programming Repetition – Do Loops.
Clojure Template Tail Recursion. Hello, Factorial! The factorial function is everybody’s introduction to recursion (defn factorial-1 [n] (if (zero? n)
Programming Logic and Design, Third Edition Comprehensive
Chapter 8 and 9 Review: Logical Functions and Control Structures Introduction to MATLAB 7 Engineering 161.
1 Chapter 11 l Basics of Recursion l Programming with Recursion Recursion.
ITERATIVE CONSTRUCTS: DOLIST Dolist is an iterative construct (a loop statement) consisting of a variable declaration and a body The body states what happens.
© Copyright 1992–2004 by Deitel & Associates, Inc. and Pearson Education Inc. All Rights Reserved. Chapter 5 - Functions Outline 5.1Introduction 5.2Program.
CS2135 Lectures on Script Position (aka: the “web compiler”)
1 Chapter 18 Recursion Dale/Weems/Headington. 2 Chapter 18 Topics l Meaning of Recursion l Base Case and General Case in Recursive Function Definitions.
Computer Science 1620 Programming & Problem Solving.
Tail Recursion. Problems with Recursion Recursion is generally favored over iteration in Scheme and many other languages – It’s elegant, minimal, can.
Fundamentals of Python: From First Programs Through Data Structures
Week 4-5 Java Programming. Loops What is a loop? Loop is code that repeats itself a certain number of times There are two types of loops: For loop Used.
Making a Timer in Alice.
20-1 Computing Fundamentals with C++ Object-Oriented Programming and Design, 2nd Edition Rick Mercer Franklin, Beedle & Associates, 1999 ISBN
Functions Part I (Syntax). What is a function? A function is a set of statements which is split off into a separate entity that can be used like a “new.
Programming with Alice Computing Institute for K-12 Teachers Summer 2011 Workshop.
CS161 Topic #21 CS161 Introduction to Computer Science Topic #2.
© The McGraw-Hill Companies, 2006 Chapter 4 Implementing methods.
9 Chapter Nine Compiled Web Server Programs. 9 Chapter Objectives Learn about Common Gateway Interface (CGI) Create CGI programs that generate dynamic.
© Copyright 1992–2004 by Deitel & Associates, Inc. and Pearson Education Inc. All Rights Reserved. C How To Program - 4th edition Deitels Class 05 University.
Lecturer: Dr. AJ Bieszczad Chapter 11 COMP 150: Introduction to Object-Oriented Programming 11-1 l Basics of Recursion l Programming with Recursion Recursion.
Chapter 11Java: an Introduction to Computer Science & Programming - Walter Savitch 1 Chapter 11 l Basics of Recursion l Programming with Recursion Recursion.
Python Programming Chapter 6: Iteration Saad Bani Mohammad Department of Computer Science Al al-Bayt University 1 st 2011/2012.
Functional Programming and Lisp. Overview In a functional programming language, functions are first class objects. In a functional programming language,
Dynamic Web Pages & JavaScript. Dynamic Web Pages Dynamic = Change Dynamic Web Pages are web pages that change. More than just moving graphics around.
CIS 234: LOOPS Adapted from materials by Dr. Donald Bell, 2000 (updated April 2007)
Computers and Scientific Thinking David Reed, Creighton University Functions and Libraries 1.
6 Chapter 61 Looping Programming Logic and Design, Second Edition, Comprehensive 6.
CPS120: Introduction to Computer Science Lecture 14 Functions.
Introduction to JavaScript CS101 Introduction to Computing.
XP Tutorial 8 Adding Interactivity with ActionScript.
Chapter 11Java: an Introduction to Computer Science & Programming - Walter Savitch 1 Chapter 11 l Basics of Recursion l Programming with Recursion Recursion.
M1G Introduction to Programming 2 3. Creating Classes: Room and Item.
Lecture on Set! And Local CS 2135 Copyright Kathi Fisler, 2002 This material requires Advanced Language Level.
Testing CSE 160 University of Washington 1. Testing Programming to analyze data is powerful It’s useless (or worse!) if the results are not correct Correctness.
PROGRAMMING IN PYTHON LETS LEARN SOME CODE TOGETHER!
Session 7 Introduction to Inheritance. Accumulator Example a simple calculator app classes needed: –AdderApp - contains main –AddingFrame - GUI –CloseableFrame.
Control flow Ruth Anderson UW CSE 160 Spring
CSIS 113A Lecture 5 Functions. Introduction to Functions  Building Blocks of Programs  Other terminology in other languages:  Procedures, subprograms,
Control flow Ruth Anderson UW CSE 160 Winter
Dr. Abdullah Almutairi Spring PHP is a server scripting language, and a powerful tool for making dynamic and interactive Web pages. PHP is a widely-used,
CMSC 104, Section 301, Fall Lecture 18, 11/11/02 Functions, Part 1 of 3 Topics Using Predefined Functions Programmer-Defined Functions Using Input.
Lets and Loops Tail Recursion.
User-Written Functions
Loops BIS1523 – Lecture 10.
CS1371 Introduction to Computing for Engineers
Intro to PHP & Variables
User-Defined Functions
Chapter 5 - Functions Outline 5.1 Introduction
Subroutines Idea: useful code can be saved and re-used, with different data values Example: Our function to find the largest element of an array might.
Functions BIS1523 – Lecture 17.
Number and String Operations
The Metacircular Evaluator
Java Programming Loops
Dynamic Scoping Lazy Evaluation
The Metacircular Evaluator
6.001 SICP Further Variations on a Scheme
Streams, Delayed Evaluation and a Normal Order Interpreter
Basics of Recursion Programming with Recursion
Week 4 Lecture-2 Chapter 6 (Methods).
Tonga Institute of Higher Education IT 141: Information Systems
Java Programming Loops
Tonga Institute of Higher Education IT 141: Information Systems
Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator
Presentation transcript:

CS2135 Lectures on Script Position

Recap: CGI scripts In the CGI protocol, there is no way to send the result of a script back to the page that invoked it. Each script must generate a new page to continue the computation. (define (find-tour) (display-trip [tour2cgi] (prompt-read-many [tour1html] “Name” “Home City”) (prompt-read-many [tour1cgi] “music?” “museums?”))) (define (tour1html) … (tour1cgi name city)) (define (tour1cgi name city) … (tour2cgi name city prefs)) (define (tour2cgi name city prefs) (display-trip name city prefs)) Text version: input commands return to give args to display-trip Web version: input commands require calls to scripts (web) (text)

Recap: CGI scripts (define (find-tour) (display-trip [tour2cgi] (prompt-read-many [tour1html] “Name” “Home City”) (prompt-read-many [tour1cgi] “music?” “museums?”))) (define (tour1html) … (tour1cgi name city)) (define (tour1cgi name city) … (tour2cgi name city prefs)) (define (tour2cgi name city prefs) (display-trip name city prefs)) Text version: input commands return to give args to display-trip Web version: input commands require calls to scripts (web) (text) To use CGI, programmers are forced to structure their code (scripts) in a particular way [functions that handle input can’t return to a pending operation]

Why does the difference in structure matter? What if a programmer needed two versions of the program (one for the web, one for another interface) – can’t reuse the code … … and would have to maintain two versions. Better programming tools exist for testing and debugging non-web versions. Difference complicates the programmers’ job

How does our CS training tell us to address this problem? Programmers write the text-I/O version Conversion program produces the web scripts When program changes, edit the text version and re-generate the scripts Implement a program to convert programs to the web! This set of lectures will teach you how the conversion to web-format works

Why are We Covering This? Web conversion illustrates the kinds of programs we can write to process other programs – programs that process other programs is one of the themes of this course. Shows you how programming languages and programming technology can impact a real-world application area such as the web The “web conversion” method actually applies to many other language issues

On to the conversion details …

Terminology: Script Position (f 4) is not in script position in (+ (f 4) 3) [because the + needs the value of (f 4)] The call to f in (f (+ 4 3)) is in script position [because the result from f is the result of the whole expression] A function call is in script-position in an expression if the value returned from the call is the value of the entire expression. Examples:

(g 6) is not in script position in (f (g 6)) the call to f is in script position in (f (g 6)) (f 6) is in script position in (cond [(= n 0) 1] [else (f 6)]) because (f 6) is the value of the cond (if else case is taken). A function call is in script-position in an expression if the value returned from the call is the value of the entire expression. Examples: Terminology: Script Position

Try it: which calls are in script position? (* (f 3) (g 5)) (cond [(foo 4) (bar 6)] [else (baz 7)]) (f (cond [(= x 0) (h 2)] [else 9]))

Try it: which calls are in script position? (* (f 3) (g 5)) (cond [(foo 4) (bar 6)] [else (baz 7)]) (f (cond [(= x 0) (h 2)] [else 9])) Call to h is not because f is waiting for the result of the cond Call to * is not because only care about user- defined functions Call to foo is not because result of cond is result of answers

Try it: which calls are in script position? (define (find-tour) (display-trip (prompt-read-many “Name” “Home City”) (prompt-read-many “music?” “museums?”))) (define (tour1html) … (tour1cgi name city)) (define (tour1cgi name city) … (tour2cgi name city prefs)) (define (tour2cgi name city prefs) (display-trip name city prefs)) (web) (text)

Try it: which calls are in script position? (define (find-tour) (display-trip (prompt-read-many “Name” “Home City”) (prompt-read-many “music?” “museums?”))) (define (tour1html) … (tour1cgi name city)) (define (tour1cgi name city) … (tour2cgi name city prefs)) (define (tour2cgi name city prefs) (display-trip name city prefs)) (web) (text) Not surprisingly, the calls in the web version are all in script position

What’s Important About Script Position? Calls that are in script position have the key characteristic of calls to web scripts: no pending computation is waiting for the result of the call Calls in script position can therefore be turned directly into invocations of web scripts Task: We need to move all calls to user-defined functions that are not in script position into script position

Moving Calls to Script Position We can move calls to script position by following a simple sequence of steps. (We’ll use the name “script” in functions that should be called only in script position) (define (fscript x) (+ x 3)) (* (fscript 5) 2) [returns 16]

Moving Calls to Script Position (define (fscript x) (+ x 3)) (* (fscript 5) 2) [returns 16] We can move calls to script position by following a simple sequence of steps. (We’ll use the name “script” in functions that should be called only in script position) Call is not in script position – must move Where would this call need to go to be in script position? Must be at the front (nothing waiting for its result)

Moving Calls to Script Position (define (fscript x) (+ x 3)) (* (fscript 5) 2) [returns 16] We can move calls to script position by following a simple sequence of steps. (We’ll use the name “script” in functions that should be called only in script position) Must be at the front (nothing waiting for its result) (define (fscript x) (+ x 3)) (fscript 5) (* 2) [returns 16] But this leaves a hole in the original expression!

Moving Calls to Script Position (define (fscript x) (+ x 3)) (* (fscript 5) 2) [returns 16] We can move calls to script position by following a simple sequence of steps. (We’ll use the name “script” in functions that should be called only in script position) Must be at the front (nothing waiting for its result) (define (fscript x) (+ x 3)) (fscript 5) (* hole 2) [returns 16] But this leaves a hole in the original expression! … so introduce a variable for the “hole”

Moving Calls to Script Position Now we have the following (not syntactically correct) Scheme expression. Let’s fix it to return the right answer. (define (fscript x) (+ x 3)) (fscript 5) (* hole 2) [should return 16] (define (fscript x) (+ x 3)) (fscript 5) (lambda (hole) (* hole 2)) [should return 16] First, we need a scope for hole. Introduce a lambda:

Moving Calls to Script Position Now we need to create one expression out of the call to fscript and the lambda that will result in 16. (define (fscript x) (+ x 3)) (fscript 5) (lambda (hole) (* hole 2)) [should return 16] What is the relationship between (fscript 5) and hole? The result from (fscript 5) needs to eventually plug the hole (since we created the hole when we moved (fscript 5) to the front). But, we need to leave fscript at the front of the expression (so it stays in script position)

Moving Calls to Script Position Now we need to create one expression out of the call to fscript and the lambda that will result in 16. We could edit the contract on fscript so that it takes a function (action) telling it what to do with its result … (define (fscript x action) (action (+ x 3))) (fscript 5) (lambda (hole) (* hole 2)) [should return 16] (define (fscript x) (+ x 3)) (fscript 5) (lambda (hole) (* hole 2)) [should return 16] Now, just pass the lambda expression as the action to fscript!

Moving Calls to Script Position Now we need to create one expression out of the call to fscript and the lambda that will result in 16. We could edit the contract on fscript so that it takes a function (action) telling it what to do with its result … (define (fscript x action) (action (+ x 3))) (fscript 5 (lambda (hole) (* hole 2))) [should return 16] (define (fscript x) (+ x 3)) (fscript 5) (lambda (hole) (* hole 2)) [should return 16] Now, just pass the lambda expression as the action to fscript!

Recap: Result of First Example (define (fscript x) (+ x 3)) (* (fscript 5) 2) [returns 16] We started with: (define (fscript x action) (action (+ x 3))) (fscript 5 (lambda (hole) (* hole 2))) And ended up with: Does the new expression also return 16?Yes!

One Minor Edit … To avoid confusing the original fscript with the converted one, we’ll adopt the convention of adding /web to the name of the function when we add the action parameter: (define (fscript/web x action) (action (+ x 3))) (fscript/web 5 (lambda (hole) (* hole 2))) Note: the parameter name “action” is suggestive, because the function you pass to action behaves like the script that you specify in the action tag in an html form …

Summary: How to Convert a Function FooScript to FooScript/web Change the name and add a parameter called action Wherever FooScript returns a value, FooScript/Web should pass that value to action. If the body of FooScript is a cond, call action on each answer. (define (myscript/web x action) (cond [(= x 4) (action 5)] [else (action 7)])) (define (myscript x) (cond [(= x 4) 5] [else 7]))

Summary: How to Move Calls into Script Position Find the script call that should happen first and move it to the front of the expression (or enclosing lambda) Replace the expression you moved with a variable (like hole – use different names each time you move a call within the same original expression though) Wrap a (lambda (hole) …) around the original expression (minus the part you pulled out) and pass this lambda expression as an argument to the script call that you moved to the front. Repeat until all script calls are in script position

Time to Try It! – Exercise 1 (define (fscript x y) (cond [(= x y) 6] [else (- y x)])) (* (+ 4 5) (fscript 10 12)) Move all calls to the scripts into script position (and modify the scripts as needed): (fscript\web (lambda (hole) (* (+ 4 5) hole))) (define (fscript\web x y action) (cond [(= x y) (action 6)] [else (action (- y x))]))

Time to Try It! – Exercise 2 (define (gscript x) (* x 6)) (define (hscript y) (+ y 5)) (+ 4 (gscript (hscript 3))) (define (gscript/web x action) (action (* x 6)) (define (hscript/web y action) (action (+ y 5)) (hscript/web 3 (lambda (box1) (+ 4 (gscript box1)))) Move the call to hscript first because it executes first

Time to Try It! – Exercise 2 (define (gscript x) (* x 6)) (define (hscript y) (+ y 5)) (+ 4 (gscript (hscript 3))) (define (gscript/web x action) (action (* x 6)) (define (hscript/web y action) (action (+ y 5)) (hscript/web 3 (lambda (box1) (+ 4 (gscript box1)))) Now move call to gscript, but leave it inside the lambda

Time to Try It! – Exercise 2 (define (gscript x) (* x 6)) (define (hscript y) (+ y 5)) (+ 4 (gscript (hscript 3))) (define (gscript/web x action) (action (* x 6)) (define (hscript/web y action) (action (+ y 5)) (hscript/web 3 (lambda (box1) (gscript box1 (lambda (box2) (+ 4 box2))))) Now move call to gscript, but leave it inside the lambda The call to gscript must remain in the lambda so that hscript runs first

Time to Try It! – Exercise 3 (output "The answer is " (+ (prompt-read-script "First number: “) (prompt-read-script "Second number: "))) (prompt-read-script “First number: ” (lambda (box1) (output “The answer is” (+ box1 (prompt-read-script “Second number: “))))) Which call goes to the outside first? Now continue with the second prompt call …

Time to Try It! – Exercise 3 (output "The answer is " (+ (prompt-read-script "First number: “) (prompt-read-script "Second number: "))) (prompt-read-script “First number: ” (lambda (box1) (prompt-read-script “Second number: “ (lambda (box2) (output (+ box1 box2)))))) Now continue with the second prompt call … If you name these lambdas, you get code that looks like the web version of the project!

Time to Try It! – Exercise 4 (define (countdown n) (cond [(zero? n) (output "Liftoff!")] [else (begin (prompt-read-script (format "t - ~a and counting“ n)) (countdown (- n 1)))])) (countdown (prompt-read-script "Time left on launch pad: ")) Think of this as a program for NASA: as countdown progresses, the program produces a progress report and expects the user to give some input to continue the countdown (the program ignores the content of the input though). First, convert the expression that calls countdown

Time to Try It! – Exercise 4 (define (countdown n) (cond [(zero? n) (output "Liftoff!")] [else (begin (prompt-read-script (format "t - ~a and counting“ n)) (countdown (- n 1)))])) (countdown (prompt-read-script "Time left on launch pad: ")) First, convert the expression that calls countdown (prompt-read/web “Time left on launch pad: “ (lambda (box) (countdown box)))

Time to Try It! – Exercise 4 (define (countdown n) (cond [(zero? n) (output "Liftoff!")] [else (begin (prompt-read-script (format "t - ~a and counting“ n)) (countdown (- n 1)))])) (countdown (prompt-read-script "Time left on launch pad: ")) Now, move the call to prompt-read-script inside countdown Where should this call move to? [think about it] It should stay inside the else: remember, cond answers are in script position and we shouldn’t call the script if n is zero

Time to Try It! – Exercise 4 (define (countdown n) (cond [(zero? n) (output "Liftoff!")] [else (begin (prompt-read-script (format "t - ~a and counting“ n)) (countdown (- n 1)))])) (countdown (prompt-read-script "Time left on launch pad: ")) (define (countdown n) (cond [(zero? n) (output "Liftoff!")] [else (prompt-read/web (format "t - ~a and counting" n) (lambda (box1) (begin box1 (countdown (- n 1)))))]))

Time to Try It! – Exercise 5 (define (count-delay-script) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))]))) (output "Total delay: " (count-delay-script)) (count-delay/web (lambda (box) (output “Total delay: “ box))) Here, the script is recursive This program asks a user to keep entering numbers at a prompt. When the user enters zero, the program prints the sum and stops. Once again, convert the output expression first …

Time to Try It! – Exercise 5 (define (count-delay-script) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))]))) Now, rename count-delay-script and add action parameter (define (count-delay/web action) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))])))

Time to Try It! – Exercise 5 (define (count-delay-script) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))]))) Next, send cond answers to action … (define (count-delay/web action) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))])))

Time to Try It! – Exercise 5 (define (count-delay-script) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))]))) Next, send cond answers to action … (define (count-delay/web action) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) (action 0)] [else (action (+ new-delay (count-delay-script)))])))

Time to Try It! – Exercise 5 (define (count-delay-script) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))]))) Now, look for calls to scripts to move (define (count-delay/web action) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) (action 0)] [else (action (+ new-delay (count-delay-script)))])))

Time to Try It! – Exercise 5 (define (count-delay-script) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))]))) Now, look for calls to scripts to move (define (count-delay/web action) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) (action 0)] [else (action (+ new-delay (count-delay-script)))])))

Time to Try It! – Exercise 5 (define (count-delay-script) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))]))) The prompt-read-script call happens first, so move it first (define (count-delay/web action) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) (action 0)] [else (action (+ new-delay (count-delay-script)))])))

Time to Try It! – Exercise 5 (define (count-delay-script) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))]))) The prompt-read-script call happens first, so move it first (define (count-delay/web action) (prompt-read/web "Delay: " (lambda (box1) (let ([new-delay box1]) (cond [(= 0 new-delay) (action 0)] [else (action (+ new-delay (count-delay-script)))])))

Time to Try It! – Exercise 5 (define (count-delay-script) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))]))) Now move the count-delay-script call (and rename to count-delay/web) (define (count-delay/web action) (prompt-read/web "Delay: " (lambda (box1) (let ([new-delay box1]) (cond [(= 0 new-delay) (action 0)] [else (action (+ new-delay (count-delay-script)))])))

Time to Try It! – Exercise 5 (define (count-delay-script) (let ([new-delay (prompt-read-script "Delay: ")]) (cond [(= 0 new-delay) 0] [else (+ new-delay (count-delay-script))]))) Now move the count-delay-script call (and rename to count-delay/web) (define (count-delay/web action) (prompt-read/web "Delay: " (lambda (box1) (let ([new-delay box1]) (cond [(= 0 new-delay) (action 0)] [else (count-delay/web (lambda (box2) (action (+ new-delay box2))))]))) Moral: recursive scripts aren’t harder to convert – follow same rules

Script Position: Recap Now done several examples, including recursive scripts After conversion, all calls to scripts are in “script position”, so can easily produce versions that would run on a webserver Student last year used this to write a web- based version of Mastermind – used the conversion to get the looping right.

What Else is Script Position Useful? Script position also helps program optmization (compilers). Consider sum (of list of numbers): (define (sum alon) (cond [(empty? alon) 0] [(cons? alon) (+ (first alon) (sum (rest alon)))])) not in script position (sum (list )) (+ 1 (sum (list 3 5 7))) (+ 1 (+ 3 (sum (list 5 7)))) (+ 1 (+ 3 (+ 5 (sum (list 7))))) (+ 1 (+ 3 (+ 5 (+ 7 (sum empty))))) (+ 1 (+ 3 (+ 5 (+ 7 0)))) (+ 1 (+ 3 (+ 5 7))) (+ 1 (+ 3 12)) (+ 1 15) 16 Example of run of sum and main steps in execution Notice the shape of the computation – grows out then shrinks

What Else is Script Position Useful? Here’s a version of sum with recursive calls in script position (define (sum2 alon) (sum-help alon 0)) (define (sum-help alon total) (cond [(empty? alon) total] [(cons? alon) (sum-help (rest alon) (+ (first alon) total))])) (sum2 (list )) (sum-help (list ) 0) (sum-help (list 3 5 7) 1) (sum-help (list 5 7) 4) (sum-help (list 7) 9) (sum-help empty 16) 16 Notice the shape of the computation now – there are no pending calls, so the expression at each step has the same size This version runs in less space than the original (won’t run out of room on the stack, whereas original sum might)

Summary Script Position (really called “tail position”) is a useful concept in programming languages Many compilers will convert certain calls to tail position as an optimization (so you can write code not in script position and still gain benefits of it) So why don’t web servers do that? Stay tuned … For now, you should be able to convert calls to script position, as we did in these exercises