Programming Languages. Function-Closure Idioms. Adapted from Dan Grossman's PL class, U. of Washington

Similar documents
CS 360 Programming Languages Day 14 Closure Idioms

CSE 341 Section Handout #6 Cheat Sheet

CSE341: Programming Languages Lecture 9 Function-Closure Idioms. Dan Grossman Fall 2011

CSE341: Programming Languages Lecture 9 Function-Closure Idioms. Dan Grossman Winter 2013

Programming Languages. Thunks, Laziness, Streams, Memoization. Adapted from Dan Grossman s PL class, U. of Washington

Scheme Quick Reference

Scheme Quick Reference

An Introduction to Scheme

CSC 533: Programming Languages. Spring 2015

Box-and-arrow Diagrams

(Func&onal (Programming (in (Scheme)))) Jianguo Lu

Vectors in Scheme. Data Structures in Scheme

The Typed Racket Guide

Streams, Delayed Evaluation and a Normal Order Interpreter. CS 550 Programming Languages Jeremy Johnson

Typed Racket: Racket with Static Types

CS 360 Programming Languages Interpreters

Functional Programming. Pure Functional Languages

4/19/2018. Chapter 11 :: Functional Languages

Scheme as implemented by Racket

Functional Programming. Pure Functional Languages

CS115 - Module 9 - filter, map, and friends

Functional Programming - 2. Higher Order Functions

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

CS 152 / SE 152 Programming Language Paradigms

Functional Programming. Big Picture. Design of Programming Languages

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

Func%onal Programming in Scheme and Lisp

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

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

Class 6: Efficiency in Scheme

Scheme: Strings Scheme: I/O

regsim.scm ~/umb/cs450/ch5.base/ 1 11/11/13

Func%onal Programming in Scheme and Lisp

INTRODUCTION TO SCHEME

Principles of Programming Languages Topic: Scope and Memory Professor Louis Steinberg Fall 2004

Rewriting your function using map and foldr

CSE413: Programming Languages and Implementation Racket structs Implementing languages with interpreters Implementing closures

Introduction to Functional Programming

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

CSCC24 Functional Programming Scheme Part 2

CSE 413 Languages & Implementation. Hal Perkins Winter 2019 Structs, Implementing Languages (credits: Dan Grossman, CSE 341)

LECTURE 16. Functional Programming

Racket: Modules, Contracts, Languages

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

SCHEME AND CALCULATOR 5b

User-defined Functions. Conditional Expressions in Scheme

Streams and Evalutation Strategies

Normal Order (Lazy) Evaluation SICP. Applicative Order vs. Normal (Lazy) Order. Applicative vs. Normal? How can we implement lazy evaluation?

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

CS 314 Principles of Programming Languages

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

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

Notes on Higher Order Programming in Scheme. by Alexander Stepanov

COP4020 Programming Assignment 1 - Spring 2011

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

CS450 - Structure of Higher Level Languages

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

Extensible Pattern Matching

Dictionaries. Looking up English words in the dictionary. Python sequences and collections. Properties of sequences and collections

Scheme. Functional Programming. Lambda Calculus. CSC 4101: Programming Languages 1. Textbook, Sections , 13.7

CSE341, Spring 2013, Final Examination June 13, 2013

Introduction to Scheme

High Performance Computing

Documentation for LISP in BASIC

4.2 Variations on a Scheme -- Lazy Evaluation

CS 314 Principles of Programming Languages

CSc 520 Principles of Programming Languages

Lecture Notes on Lisp A Brief Introduction

Lecture #24: Programming Languages and Programs

Functional Programming

CS 440: Programming Languages and Translators, Spring 2019 Mon

CIS4/681 { Articial Intelligence 2 > (insert-sort '( )) ( ) 2 More Complicated Recursion So far everything we have dened requires

Lecture 4: Higher Order Functions

Sample Final Exam Questions

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

Procedural abstraction SICP Data abstractions. The universe of procedures forsqrt. Procedural abstraction example: sqrt

Turtles All The Way Down

OCaml Language Choices CMSC 330: Organization of Programming Languages

Functional Programming Languages (FPL)

A LISP Interpreter in ML

CS113: Lecture 3. Topics: Variables. Data types. Arithmetic and Bitwise Operators. Order of Evaluation

Booleans (aka Truth Values) Programming Languages and Compilers (CS 421) Booleans and Short-Circuit Evaluation. Tuples as Values.

Local definitions and lexical scope

Local definitions and lexical scope. Local definitions. Motivating local definitions. s(s a)(s b)(s c), where s = (a + b + c)/2.

CSE 341: Programming Languages

An introduction to Scheme

TAIL RECURSION, SCOPE, AND PROJECT 4 11

How to Design Programs

The Haskell HOP: Higher-order Programming

Parsing Scheme (+ (* 2 3) 1) * 1

Administrivia. Simple data types

Chapter 15 Functional Programming Languages

Introduction to Typed Racket. The plan: Racket Crash Course Typed Racket and PL Racket Differences with the text Some PL Racket Examples

Symbolic Programming. Dr. Zoran Duric () Symbolic Programming 1/ 89 August 28, / 89

CS61A Midterm 2 Review (v1.1)

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

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?

Modern Programming Languages. Lecture LISP Programming Language An Introduction

1.3. Conditional expressions To express case distinctions like

Functional Programming. Pure Functional Programming

Transcription:

Programming Languages Function-Closure Idioms Adapted from Dan Grossman's PL class, U. of Washington

More idioms We know the rule for lexical scope and function closures Now what is it good for A partial but wide-ranging list: Pass functions with private data to iterators (map/filter): Done Combine functions (e.g., composition) Currying (multi-arg functions and partial application) Callbacks (e.g., in reactive programming) Implementing an ADT with a record of functions 2

Combine functions Canonical example is function composition: (define (compose f g) (lambda (x) (f (g x)))) Creates a closure that remembers what f and g are bound to This function is built-in to Racket; but this definition is basically how it works. 3rd version is the best (clearest as to what it does): (define (sqrt-of-abs i) (sqrt (abs i))) (define (sqrt-of-abs i) ((compose sqrt abs) i)) (define sqrt-of-abs (compose sqrt abs)) 3

Currying and Partial Application Currying is the idea of calling a function with an incomplete set of arguments. When you "curry" a function, you get a function back that accepts the remaining arguments. Named after Haskell Curry, who studied related ideas in logic. Useful in situations where you want to call/pass a function, but you don't know the values for all the arguments yet. Ex: a function of two arguments, but coming from two separate places (scopes) in your program. 6

Motivation example We want to write code that takes a list of numbers and returns a list of the number 4 raised to the power of each number. in: (x1 x2 xn)! out: (4^x1 4^x2 4^xn)! We could use a lambda expression: (map (lambda (x) (expt 4 x)) lst)! But this can get tedious to do over and over. What if the expt function were defined differently? 7

Currying and Partial Application We know (expt x y) raises x to the y'th power. We could define a different version of expt like this: (define (expt-curried x) (lambda (y) (expt x y))! We can call this function like this: ((expt-curried 4) 2)! This is an incredibly flexible definition: We can call with two arguments as normal (with extra parens) Or call with one argument to get a function that accepts the remaining argument. This is critical in some other functional languages (albeit, not Racket or Scheme) where functions may have at most one argument. 8

Currying and Partial Application Currying is still useful in Racket with the curry function: Turns a function (f x1 x2 x3 xn) into a function ((((f x1) x2) x3) xn)! curry takes a function f and some optional arguments Returns a function that accumulates remaining arguments until f can be called (all arguments are present). (curry expt 4) == (expt-curried 4)! ((curry expt 4) 2) == ((expt-curried 4) 2)! These can be useful in definitions themselves: (define (double x) (* 2 x))! (define double (curry * 2))! 9

Currying and Partial Application Currying is also useful to shorten longish lambda expressions: Old way: (map (lambda (x) (+ x 1)) '(1 2 3))! New way: (map (curry + 1) '(1 2 3))! Great for encapsulating private data: list-ref is the built-in get-nth. (define get-month (curry list-ref '(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)))! This example introduces a new datatype: symbol. Symbols are similar to strings, except they don't have quotes around them (and you can't take them apart or add them together like strings). 10

Currying and Partial Application But this gives zero-based months: (define get-month (curry list-ref!! '(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))) Let's subtract one from the argument first: (define get-month (compose (curry list-ref! '(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)) (curryr - 1))) curryr curries from right to left, rather than left to right. 11

Currying and Partial Application Another example: (define (eval-polynomial coeff x)! (if (null? coeff) 0!! (+ (* (car coeff) (expt x (- (length coeff) 1))) (eval-polynomial (cdr coeff) x))))! (define (make-polynomial coeff)! (lambda (x) (eval-polynomial coeff x)) (define make-polynomial (curry eval-polynomial))! 12

Currying and Partial Application A few more examples: (map (compose (curry + 2) (curry * 4)) '(1 2 3))! quadruples then adds two to the list '(1 2 3) (filter (curry < 10) '(6 8 10 12))! Careful! curry works from the left, so (curry < 10) is equivalent to (lambda (x) (< 10 x)) so this filter keeps numbers that are greater than 10. Probably clearer to do: (filter (curryr > 10) '(6 8 10 12))! (In this case, the confusion is because we are used to "<" being an infix operator). 13

Return to the foldr J Currying becomes really powerful when you curry higher-order functions. Recall (foldr f init (x1 x2 xn)) returns (f x1 (f x2 (f xn-2 (f xn-1 (f xn init))! (define (sum-list-ok lst) (foldr + 0 lst)) (define sum-list-super-cool (curry foldr + 0) 16

Another example Scheme and Racket have andmap and ormap. (andmap f (x1 x2 )) returns (and (f x1) (f x2) )! (ormap f (x1 x2 )) returns (or (f x1) (f x2) )! (andmap (curryr > 7) '(8 9 10)) è #t (ormap (curryr > 7) '(4 5 6 7 8)) è #t (ormap (curryr > 7) '(4 5 6)) è #f (define contains7 (curry ormap (curry = 7))) (define all-are7 (curry andmap (curry = 7))) 17

Another example Currying and partial application can be convenient even without higherorder functions. Note: (range a b) returns a list of integers from a to b-1, inclusive. (define (zip lst1 lst2) (if (null? lst1) '() (cons (list (car lst1) (car lst2)) (zip (cdr lst1) (cdr lst2))))) (define countup (curry range 1)) (define (add-numbers lst) (zip (countup (length lst)) lst)) 18

When to use currying When you write a lambda function of the form (lambda (y1 y2 ) (f x1 x2 y1 y2 )) You can replace that with (curry f x1 x2 ) Similarly, replace (lambda (y1 y2 ) (f y1 y2 x1 x2 )) with (curryr f x1 x2 ) 19

When to use currying Try these: Assuming lst is a list of numbers, write a call to filter that keeps all numbers greater than 4. Assuming lst is a list of lists of numbers, write a call to map that adds a 1 to the front of each sublist. Assuming lst is a list of numbers, write a call to map that turns each number (in lst) into the list (1 number). Assuming lst is a list of numbers, write a call to map that squares each number (you should curry expt). Define a function dist-from-origin in terms of currying a function (dist x1 y1 x2 y2) [assume dist is already defined elsewhere] 20

Callbacks A common idiom: Library takes functions to apply later, when an event occurs examples: When a key is pressed, mouse moves, data arrives When the program enters some state (e.g., turns in a game) A library may accept multiple callbacks Different callbacks may need different private data with different types (Can accomplish this in C++ with objects that contain private fields.) 24

Mutable state While it s not absolutely necessary, mutable state is reasonably appropriate here We really do want the callbacks registered and events that have been delivered to change due to function calls In "pure" functional programming, there is no mutation. Therefore, it is guaranteed that calling a function with certain arguments will always return the same value, no matter how many times it's called. Not guaranteed once mutation is introduced. This is why global variables are considered "bad" in languages like C or C++ (global constants OK). 25

Mutable state: Example in C++ times_called = 0!! int function() { times_called++; return times_called;! }! This is useful, but can cause big problems if somebody else modifies times_called from elsewhere in the program. 26

Mutable state Scheme and Racket's variables are mutable. The name of any function which does mutation contains a "!" Mutate a variable with set!! Only works after the variable has been placed into an environment with define, let, or as an argument to a function. set! does not return a value. (define times-called 0)! (define (function) (set! times-called (+ 1 times-called)) times-called)! Notice that functions that have side-effects or use mutation are the only functions that need to have bodies with more than one expression in them. 27

Example call-back library Library maintains mutable state for what callbacks are there and provides a function for accepting new ones A real library would support removing them, etc. (define callbacks '()) (define (add-callback func) (set! callbacks (cons func callbacks))) (define (key-press which-key) (for-each (lambda (func) (func which-key)) callbacks)) 29

Clients (define (print-if-pressed key message) (add-callback (lambda (which-key) (if (string=? key which-key) (begin (display message) (newline)) #f)))) (define count-presses 0) (add-callback (lambda (key) (set! count-presses (+ 1 count-presses)) (display "total presses = ") (display count-presses) (newline))) 31

Improvement on the client side Why clutter up the global environment with count-presses? We don't want some other function mucking with that variable. Let's hide it inside a let that only our callback can access. (let ((count-presses 0)) (add-callback (lambda (key) (set! count-presses (+ 1 count-presses)) (display "total presses = ") (display count-presses) (newline))) 32

Implementing an ADT As our last pattern, closures can implement abstract data types They can share the same private data Private data can be mutable or immutable Feels quite a bit like objects, emphasizing that OOP and functional programming have similarities The actual code is advanced/clever/tricky, but has no new features Combines lexical scope, closures, and higher-level functions Client use is not so tricky 33

(define (new-stack)! (let ((the-stack '()))! (define (dispatch method-name)! (cond ((eq? method-name 'empty?) empty?)! ((eq? method-name 'push) push)! ((eq? method-name 'pop) pop)! (#t (error "Bad method name"))))! (define (empty?) (null? the-stack))! (define (push item) (set! the-stack (cons item the-stack)))! (define (pop)! (if (null? the-stack) (error "Can't pop an empty stack")! (let ((top-item (car the-stack)))! (set! the-stack (cdr the-stack))! top-item)))! dispatch)) ; this last line is the return value ; of the let statement at the top.! 34