CSC324 Functional Programming Efficiency Issues, Parameter Lists

Similar documents
CSCC24 Functional Programming Scheme Part 2

Principles of Programming Languages Topic: Functional Programming Professor L. Thorne McCarty Spring 2003

Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

Functional Programming. Pure Functional Languages

Functional Programming. Pure Functional Languages

SCHEME 8. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. March 23, 2017

afewadminnotes CSC324 Formal Language Theory Dealing with Ambiguity: Precedence Example Office Hours: (in BA 4237) Monday 3 4pm Wednesdays 1 2pm

Tail Recursion. ;; a recursive program for factorial (define fact (lambda (m) ;; m is non-negative (if (= m 0) 1 (* m (fact (- m 1))))))

Announcements. The current topic: Scheme. Review: BST functions. Review: Representing trees in Scheme. Reminder: Lab 2 is due on Monday at 10:30 am.

SCHEME 7. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. October 29, 2015

Introduction to Functional Programming in Racket. CS 550 Programming Languages Jeremy Johnson

Functional Languages. Hwansoo Han

Fall 2017 Discussion 7: October 25, 2017 Solutions. 1 Introduction. 2 Primitives

LECTURE 16. Functional Programming

CS450 - Structure of Higher Level Languages

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

TAIL RECURSION, SCOPE, AND PROJECT 4 11

User-defined Functions. Conditional Expressions in Scheme

Fall 2018 Discussion 8: October 24, 2018 Solutions. 1 Introduction. 2 Primitives

Spring 2018 Discussion 7: March 21, Introduction. 2 Primitives

Functional Programming. Big Picture. Design of Programming Languages

Functional Programming

Organization of Programming Languages CS3200/5200N. Lecture 11

Intro. Scheme Basics. scm> 5 5. scm>

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

An Introduction to Scheme

Functional Programming. Pure Functional Programming

Streams and Evalutation Strategies

An introduction to Scheme

SCHEME AND CALCULATOR 5b

Chapter 1. Fundamentals of Higher Order Programming

More Scheme CS 331. Quiz. 4. What is the length of the list (()()()())? Which element does (car (cdr (x y z))) extract from the list?

SCHEME 10 COMPUTER SCIENCE 61A. July 26, Warm Up: Conditional Expressions. 1. What does Scheme print? scm> (if (or #t (/ 1 0)) 1 (/ 1 0))

;;; Determines if e is a primitive by looking it up in the primitive environment. ;;; Define indentation and output routines for the output for

CS 61A Interpreters, Tail Calls, Macros, Streams, Iterators. Spring 2019 Guerrilla Section 5: April 20, Interpreters.

1.3. Conditional expressions To express case distinctions like

Class 6: Efficiency in Scheme

Functional Programming Languages (FPL)

Quick announcement. Midterm date is Wednesday Oct 24, 11-12pm.

CS1 Recitation. Week 2

6.001 Recitation 23: Register Machines and Stack Frames

CSE 413 Midterm, May 6, 2011 Sample Solution Page 1 of 8

CSC 533: Programming Languages. Spring 2015

SCHEME The Scheme Interpreter. 2 Primitives COMPUTER SCIENCE 61A. October 29th, 2012

Interpreters and Tail Calls Fall 2017 Discussion 8: November 1, 2017 Solutions. 1 Calculator. calc> (+ 2 2) 4

Scheme Quick Reference

CS61A Notes 02b Fake Plastic Trees. 2. (cons ((1 a) (2 o)) (3 g)) 3. (list ((1 a) (2 o)) (3 g)) 4. (append ((1 a) (2 o)) (3 g))

CS 314 Principles of Programming Languages

Introduction to Functional Programming in Haskell 1 / 56

Programming Language Pragmatics

CS61A Midterm 2 Review (v1.1)

G Programming Languages - Fall 2012

Wellesley College CS251 Programming Languages Spring, 2000 FINAL EXAM REVIEW PROBLEM SOLUTIONS

Scheme: Data. CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Monday, April 3, Glenn G.

CS 135 Winter 2018 Tutorial 7: Accumulative Recursion and Binary Trees. CS 135 Winter 2018 Tutorial 7: Accumulative Recursion and Binary Trees 1

Programming Languages

Scheme Quick Reference

Computer Science 21b (Spring Term, 2015) Structure and Interpretation of Computer Programs. Lexical addressing

CONCEPTS OF PROGRAMMING LANGUAGES Solutions for Mid-Term Examination

A Brief Introduction to Scheme (I)

Scheme as implemented by Racket

Functional Programming - 2. Higher Order Functions

Typed Scheme: Scheme with Static Types

Repetition Through Recursion

Functional Programming

INTERPRETERS 8. 1 Calculator COMPUTER SCIENCE 61A. November 3, 2016

ENVIRONMENT DIAGRAMS AND RECURSION 2

Principles of Programming Languages

RACKET BASICS, ORDER OF EVALUATION, RECURSION 1

Functional programming with Common Lisp

61A LECTURE 22 TAIL CALLS, ITERATORS. Steven Tang and Eric Tzeng July 30, 2013

HIERARCHICAL DATA What is a Tree? How is it different from a Deep List? When would you use one over the other?

FP Foundations, Scheme

Project 2: Scheme Interpreter

CS 342 Lecture 7 Syntax Abstraction By: Hridesh Rajan

Chapter 15. Functional Programming Languages

CS 275 Name Final Exam Solutions December 16, 2016

Recap: Functions as first-class values

Understanding Recursion

CSC 1052 Algorithms & Data Structures II: Linked Lists Revisited

Evaluating Scheme Expressions

Scheme Tutorial. Introduction. The Structure of Scheme Programs. Syntax

CPS 506 Comparative Programming Languages. Programming Language Paradigm

CSc 520 Principles of Programming Languages

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

6.001 SICP. Types. Types compound data. Types simple data. Types. Types procedures

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


CS61A Summer 2010 George Wang, Jonathan Kotker, Seshadri Mahalingam, Eric Tzeng, Steven Tang

Working with recursion. From definition to template. Readings: HtDP, sections 11, 12, 13 (Intermezzo 2).

Macros & Streams Spring 2018 Discussion 9: April 11, Macros

JVM ByteCode Interpreter

6.001 Notes: Section 8.1

Working with recursion

CMSC 330: Organization of Programming Languages. Operational Semantics

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

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

Processadors de Llenguatge II. Functional Paradigm. Pratt A.7 Robert Harper s SML tutorial (Sec II)

Discussion 11. Streams

Chapter 11 :: Functional Languages

Transcription:

CSC324 Functional Programming Efficiency Issues, Parameter Lists Afsaneh Fazly 1 January 28, 2013 1 Thanks to A.Tafliovich, P.Ragde, S.McIlraith, E.Joanis, S.Stevenson, G.Penn, D.Horton 1

Example: efficiency issues ;; Pre: l1 and l2 are lists ;; Return -1 if both lists are empty, ;; otherwise return length of the longer list (define (longest-nonzero l1 l2) (cond ((and (null? l1) (null? l2)) -1) ((> (length l1) (length l2)) (length l1)) (else (length l2)))) Problem?

efficiency issues Example: ;; Pre: l1 and l2 are lists ;; Return -1 if both lists are empty, ;; otherwise return length of the longer list (define (longest-nonzero l1 l2) (cond ((and (null? l1) (null? l2)) -1) ((> (length l1) (length l2)) (length l1)) (else (length l2)))) Problem? evaluating the same expressions more than once. Any ideas how to solve this?

efficiency issues: helper procedures Solution 1: bind values to parameters using a helper procedure. (define (maximum x y) (if (> x y) x y)) (define (longest-nonzero l1 l2) (cond ((and (null? l1) (null? l2)) -1) (else (maximum (length l1) (length l2))))) Notes: there is a built-in max function. helper procedures are an important and useful tool.

efficiency issues: binding constructs Solution 2: use a binding construct such as let to create local bindings: (let ([id1 expr1]... [idn exprn]) body ) creates local bindings of identifiers to expression values. scope of these bindings is the body of let. evaluation: expr1,, exprn are evaluated in some undefined order, saved, and then bound to id1,, idn. evaluations have the appearance of being done in parallel.

let: example (define a 100) (define b 200) (define c 300) (let ([a 5] [b (+ a a)] [c (+ a b)]) (list a b c) ) Result?

Consider: let: example (define sq-cube (lambda (x) (let ([sqr (* x x)] [cube (* x (* x x))]) (list sqr cube)))) Result of evaluating (sq-cube 3)?

Consider: let: example (define sq-cube (lambda (x) (let ([sqr (* x x)] [cube (* x (* x x))]) (list sqr cube)))) Result of evaluating (sq-cube 3)? (9 27) Want to reuse sqr.

Reusing sqr: let: example (define sq-cube (lambda (x) (let ([sqr (* x x)] [cube (* x sqr)]) (list sqr cube)))) Result of evaluating (sq-cube 3)?

10 let: example Reusing sqr: (define sq-cube (lambda (x) (let ([sqr (* x x)] [cube (* x sqr)]) (list sqr cube)))) Result of evaluating (sq-cube 3)? Error! Why doesn t this work?

11 let: example Reusing sqr: (define sq-cube (lambda (x) (let ([sqr (* x x)] [cube (* x sqr)]) (list sqr cube)))) Result of evaluating (sq-cube 3)? Error! Why doesn t this work? sqr is undefined at the time of evaluating (* x sqr). Any ideas how to solve this?

Solution 1: use nested let let: example (define sq-cube (lambda (x) (let ([sqr (* x x)]) (let ([cube (* x sqr)]) (list sqr cube) )))) Why does this work?

Solution 1: use nested let let: example (define sq-cube (lambda (x) (let ([sqr (* x x)]) (let ([cube (* x sqr)]) (list sqr cube) )))) Why does this work? scope of each binding is the body of let scope of sqr (* x x) is (let ([cube (* x sqr)]) (list sqr cube) )

let* Solution 2: use let* (let* ([id1 expr1]... [idn exprn]) body ) scope of each binding is the part of the let*-expression to the right of the binding. evaluation: expr1,, exprn are evaluated sequentially, from left to right.

15 sq-cube with let*: let* (define sq-cube (lambda (x) (let* ([sqr (* x x)] [cube (* x sqr)]) (list sqr cube))))

let versus letrec (let ([sumup (lambda (x) (cond ([zero? x] 0) (else (+ x (sumup (- x 1))))))] [s (sumup 10)]) (list s)) What is the result?

let versus letrec (letrec ([sumup (lambda (x) (cond ([zero? x] 0) (else (+ x (sumup (- x 1))))))] [s (sumup 10)]) (list s))

letrec (letrec ([id1 expr1]... [idn exprn]) body ) scope: each binding has the entire letrec expression as its region (including the bindings and body). evaluation: expr1,..., exprn are evaluated saved, and then bound to id1,, idn. commonly used for defining local recursive helper procedures.

letrec example: mutually recursive procedures (letrec ([my-even? (lambda (x) (if (= x 0) #t (my-odd? (- x 1))))] [my-odd? (lambda (x) (if (= x 0) #f (my-even? (- x 1))))]) (if (and (my-even? 4) (not (my-odd? 4)) (not (my-even? 5))) 42 0)) Result?

example: simple Fibonacci ;; simple (inefficient) Fibonacci (define fib (lambda (n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fib (- n 1)) (fib (- n 2)))))))

faster Fibonacci: using accumulators and helper procedure ;; faster Fibonacci: using accumulators to ;; improve efficiency (define fastfib (lambda (p1 p2 i n) (if (= i n) p1 (fastfib p2 (+ p1 p2) (+ i 1) n)))) (define fib (lambda (n) (fastfib 0 1 0 n)))

faster Fibonacci: local helper procedure using letrec ;; faster Fibonacci: using letrec (define (fib n) (letrec ([fastfib (lambda (p1 p2 i n) (if (= i n) p1 (fastfib p2 (+ p1 p2) (+ i 1) n)))]) (fastfib 0 1 0 n)))

faster Fibonacci: let vs. letrec ;; faster Fibonacci: using let? (define (fib n) (let ([fastfib (lambda (p1 p2 i n) (if (= i n) p1 (fastfib p2 (+ p1 p2) (+ i 1) n)))]) (fastfib 0 1 0 n))) Does this work?

faster Fibonacci: let vs. letrec ;; faster Fibonacci: using let? (define (fib n) (let ([fastfib (lambda (p1 p2 i n) (if (= i n) p1 (fastfib p2 (+ p1 p2) (+ i 1) n)))]) (fastfib 0 1 0 n))) Does this work? No. Scope of fastfib is the body of let.

25 (let ([x 2]) (* x x)) versions of let: examples (let ([x 4] [y (+ x 2)]) (* x y)) (let ([x 4]) (let ([y (+ x 2)]) (* x y))) (let* ([x 4] [y (+ x 2)]) (* x y))

25 (let ([x 2]) (* x x)) 4 versions of let: examples (let ([x 4] [y (+ x 2)]) (* x y)) error: unbound variable x (let ([x 4]) (let ([y (+ x 2)]) (* x y))) 24 (let* ([x 4] [y (+ x 2)]) (* x y)) 24

bindings in let and let* (let ((id1 e1)...(idn en)) body-expr) ((lambda (id1...idn) body-expr) e1...en) AND (let* ((id1 e1) (id2 e2)) body-expr) ((lambda (id1) ((lambda (id2) body-expr) e2)) e1) The two constructs let and lambda are equivalent in what they evaluate to. Binding of values to identifiers is by parameter passing OR lambda reduction no assignment

(let ([a 5] [b 10]) (+ a b)) let and lambda reduction: examples => a bound to 5, b bound to 10 => evaluate (+ a b) by substitution => evaluate (+ 5 b) => evaluate (+ 5 10) => 15 ((lambda (a b) (+ a b)) 5 10) => a bound to 5, b bound to 10 => evaluate (+ a b) by substitution => evaluate (+ 5 b) => evaluate (+ 5 10) => 15

parameter lists Recall lambda-expression: (lambda (formal-params) <body>) where (formal-params) specifies a list of N parameters. What if we do not know the exact number of actual arguments?

parameter lists Recall lambda-expression: (lambda (formal-params) <body>) where (formal-params) specifies a list of N parameters. What if we do not know the exact number of actual arguments? use parameter lists, as in: (lambda formal-params <body>) where formal-params binds a formal parameter to a (possibly empty) list of actual parameters.

Compare proc1 and proc2: (define proc1 (lambda (x) <body>)) parameter lists (proc1) ==> Error! requires exactly one argument (proc1 a) ==> x is bound to a (proc1 a b c) ==> Error! requires exactly one argument (define proc2 (lambda x <body>)) (proc2) ==> x is bound to () (proc2 a) ==> x is bound to (a) (proc2 a b c) ==> x is bound to (a b c)

parameter lists: example (define list-args (lambda varparam varparam)) (list-args) ==> () (list-args a) ==> (a) (list-args a b c d) ==> (a b c d)

parameter lists: example (define rev-args (lambda varparam (reverse varparam))) (rev-args ) ==> () (rev-args a b c) ==> (c b a) (rev-args 5 4 3 2 1) ==> (1 2 3 4 5)

parameter lists: specifying optional parameters (define proc3 (lambda (x. y) <body>)) (proc3 1) ==> x is bound to 1; y is bound to () (proc3 1 2) ==> x is bound to 1; y is bound to (2) (proc3 1 2 3) ==> x is bound to 1; y is bound to (2 3) (proc3) ==> Error: requires at least 1 argument

parameter lists for optional parameters: example (define sum-non1-args (lambda (first-par. varparam) (apply + varparam))) (sum-non1-args 1) ==> 0 (sum-non1-args 1 2) ==> 2 (sum-non1-args 1 2 3) ==> 5 (sum-non1-args ) ==> Error: requires at least 1 argument

parameter lists for optional parameters: example (define sum-non12-args (lambda (first-par sec-par. varparam) (apply + varparam))) (sum-non12-args 1 2) ==> 0 (sum-non12-args 1 2 3 4) ==> 7 (sum-non12-args 1) ==> Error: requires at least 2 arguments

pure functional languages Programs are viewed as collections of functions. Execution of programs is viewed as evaluation.

36 pure functional languages Referential transparency: The value of a function application is independent of the context in which it occurs. value of f(a,b,c) depends only on values of f, a, b and c. it does not depend on the global state of computation. A language is referentially transparent if we may replace one expression with another of equal value anywhere in a program without changing the meaning of the program.

pure functional languages Referential transparency: Main advantage: facilitates reasoning about programs and applying program transformations. Aside: Referential transparency is no longer considered a distinguishing feature of functional programming languages. It arguably holds in well-designed imperative languages too. See Mitchell, page 78 for further discussion.

pure functional languages No assignment statement: Variables are bound to values only through the association of actual parameters to formal parameters in function calls. A variable may not have a value, or its value may be a function that has not been applied to its arguments yet.

pure functional languages No assignment statement: Variables in pure FP are said to be logical in that, having acquired a value in the course of an evaluation, they retain that value until the end of evaluation. Similar to how variables are used in mathematics. Remember when you had to unlearn your mathematics training to make sense of x := x+1? In FP, this is anathema!

40 No side effects: pure functional languages Function calls have no side effects. No need to consider global state. Programs are easier to reason about. Programs are easier to prove correct.

41 pure functional languages Functions are first-class values: Can be returned as the value of an expression. Can be passed as an argument. Can be put in a data structure as a value. Unnamed functions exist as values.

42 pure functional languages Control Flow: conditionals and recursion recursion vs. iteration: In pure FP, recursion is generally preferred as a matter of style to iterative constructs like while-loops or for-loops. This makes programs easier to prove correct, easier to conceptualize as functions: Recursions, like functions, identify the structure of one or more arguments as the only values upon which the computation (and termination) depends.

43 pure functional languages Support higher-level programming: All storage management is implicit: we don t have to think about how program state maps to a computer s memory (or at least, not until we want to write super-efficient code). That means no assignment, no new/free calls to manage our own memory, and no pointers. The state of a computation is much easier to think about.

44 structural recursion Processing recursively-structured data (e.g., a list), by decomposing it into its structural components (e.g., first & rest of the list), and then processing those components. (define my-func (lambda (lst) (cond ((empty? lst)... ) (else... (first lst)... (my-func (rest lst))... ))))

45 tail-recursion The recursive call is in the last function application in function body, i.e., there is nothing to do after the function returns except return its value. Tail-recursion is implemented very efficiently and should be used whenever possible.

recursion Linear recursion: there is at most one recursive call made in any execution of function body. Flat recursion: recursion applied over top items of a (nested) list. Deep recursion: (aka tree recursion) recursion applied over all items. Mutual recursion: functions call each other, rather than themselves.