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

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

CSci 4223 Principles of Programming Languages

CSE341: Programming Languages Winter 2018 Unit 3 Summary Zach Tatlock, University of Washington

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

CSE 341 Section 5. Winter 2018

CSE341 Section 3. Standard-Library Docs, First-Class Functions, & More

CSE 341 : Programming Languages

CSE341: Programming Languages Lecture 7 First-Class Functions. Dan Grossman Winter 2013

CSE341 Autumn 2017, Midterm Examination October 30, 2017

CSE341, Fall 2011, Midterm Examination October 31, 2011

CSE341 Spring 2016, Midterm Examination April 29, 2016

CS Lecture 6: Map and Fold. Prof. Clarkson Spring Today s music: Selections from the soundtrack to 2001: A Space Odyssey

CSE341 Spring 2016, Midterm Examination April 29, 2016

CSE341, Fall 2011, Midterm Examination October 31, 2011

CSE341: Programming Languages Lecture 11 Type Inference. Dan Grossman Spring 2016

CSCI-GA Scripting Languages

Tuples. CMSC 330: Organization of Programming Languages. Examples With Tuples. Another Example

CSE341 Spring 2017, Midterm Examination April 28, 2017

CSE341: Programming Languages Lecture 4 Records, Datatypes, Case Expressions. Dan Grossman Spring 2013

CS Lecture 6: Map and Fold. Prof. Clarkson Fall Today s music: Selections from the soundtrack to 2001: A Space Odyssey

CSE 341: Programming Languages

CSE3322 Programming Languages and Implementation

CSE 505: Concepts of Programming Languages

Announcements. CSCI 334: Principles of Programming Languages. Lecture 5: Fundamentals III & ML

Higher-Order Functions

CMSC330. Objects, Functional Programming, and lambda calculus

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

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

CS 360 Programming Languages Day 14 Closure Idioms

Lists. Michael P. Fourman. February 2, 2010

Haske k ll An introduction to Functional functional programming using Haskell Purely Lazy Example: QuickSort in Java Example: QuickSort in Haskell

An introduction introduction to functional functional programming programming using usin Haskell

CMSC 330, Fall 2013, Practice Problems 3

CSE341, Spring 2013, Final Examination June 13, 2013

Part I: Written Problems

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

CMSC 330: Organization of Programming Languages. Functional Programming with Lists

CMSC 330: Organization of Programming Languages. Functional Programming with Lists

CSci 4223 Lecture 12 March 4, 2013 Topics: Lexical scope, dynamic scope, closures

CSCI-GA Final Exam

Chapter 3 Linear Structures: Lists

List Functions, and Higher-Order Functions

CMSC 330: Organization of Programming Languages. OCaml Imperative Programming

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

OCaml. ML Flow. Complex types: Lists. Complex types: Lists. The PL for the discerning hacker. All elements must have same type.

Redefinition of an identifier is OK, but this is redefinition not assignment; Thus

CSE 341, Autumn 2015, Ruby Introduction Summary

CPL 2016, week 10. Clojure functional core. Oleg Batrashev. April 11, Institute of Computer Science, Tartu, Estonia

Recap: Functions as first-class values

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

Chapter 3 Linear Structures: Lists

CSE 130: Programming Languages. Polymorphism. Ranjit Jhala UC San Diego

CMSC 330: Organization of Programming Languages. OCaml Imperative Programming

CSE341: Programming Languages Lecture 19 Introduction to Ruby and OOP. Dan Grossman Winter 2013

CSE 341 : Programming Languages Midterm, Spring 2015

Exercises on ML. Programming Languages. Chanseok Oh

CSE 341: Programming Languages

Introduction to OCaml

Datatype declarations

Abram Hindle Kitchener Waterloo Perl Monger October 19, 2006

The Haskell HOP: Higher-order Programming

Notes from a Short Introductory Lecture on Scala (Based on Programming in Scala, 2nd Ed.)

A Functional Evaluation Model

Lectures 24 and 25: Scheduling; Introduction to Effects

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

Standard ML. Curried Functions. ML Curried Functions.1

SNU Programming Language Theory

CSC324- TUTORIAL 5. Shems Saleh* *Some slides inspired by/based on Afsaneh Fazly s slides

UMBC CMSC 331 Final Exam

Lecture 4: Higher Order Functions

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

Ruby logistics. CSE341: Programming Languages Lecture 19 Introduction to Ruby and OOP. Ruby: Not our focus. Ruby: Our focus. A note on the homework

CSE 341: Programming Languages

A quick introduction to SML

CS 457/557: Functional Languages

Variables and Bindings

News. CSE 130: Programming Languages. Environments & Closures. Functions are first-class values. Recap: Functions as first-class values

Lists. Adrian Groza. Department of Computer Science Technical University of Cluj-Napoca

CSE 341, Autumn 2005, Assignment 3 ML - MiniML Interpreter

# true;; - : bool = true. # false;; - : bool = false 9/10/ // = {s (5, "hi", 3.2), c 4, a 1, b 5} 9/10/2017 4

CSE 130 [Winter 2014] Programming Languages

Some Advanced ML Features

CS152: Programming Languages. Lecture 7 Lambda Calculus. Dan Grossman Spring 2011

02157 Functional Programming. Michael R. Ha. Lecture 2: Functions, Types and Lists. Michael R. Hansen

CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Dan Grossman Spring 2011

L3 Programming September 19, OCaml Cheatsheet

SML A F unctional Functional Language Language Lecture 19

Dialects of ML. CMSC 330: Organization of Programming Languages. Dialects of ML (cont.) Features of ML. Functional Languages. Features of ML (cont.

CSc 372 Comparative Programming Languages

Lecture 2: The Basis of SML

Haskell: Lists. CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Friday, February 24, Glenn G.

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

CSE341: Programming Languages Lecture 25 Subtyping for OOP; Comparing/Combining Generics and Subtyping. Dan Grossman Winter 2013

CSc 372. Comparative Programming Languages. 8 : Haskell Function Examples. Department of Computer Science University of Arizona

Programming Languages and Compilers (CS 421)

CMSC 330, Fall 2013, Practice Problem 3 Solutions

n n Try tutorial on front page to get started! n spring13/ n Stack Overflow!

List Processing in Ocaml

Whereweare. CS-XXX: Graduate Programming Languages. Lecture 7 Lambda Calculus. Adding data structures. Data + Code. What about functions

Background. CMSC 330: Organization of Programming Languages. Useful Information on OCaml language. Dialects of ML. ML (Meta Language) Standard ML

Transcription:

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

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: 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: fun compose (g,h) = fn x => g (h x) Creates a closure that remembers what g and h are bound to Type ('b -> 'c) * ('a -> 'b) -> ('a -> 'c) but the REPL prints something equivalent ML standard library provides this as infix operator o Example (third version best): fun sqrt_of_abs i = Math.sqrt(Real.fromInt(abs i)) fun sqrt_of_abs i = (Math.sqrt o Real.fromInt o abs) i val sqrt_of_abs = Math.sqrt o Real.fromInt o abs 3

Left-to-right or right-to-left val sqrt_of_abs = Math.sqrt o Real.fromInt o abs As in math, function composition is right to left take absolute value, convert to real, and take square root square root of the conversion to real of absolute value Pipelines of functions are common in functional programming and many programmers prefer left-to-right Can define our own infix operator This one is very popular (and predefined) in F# infix > fun x > f = f x fun sqrt_of_abs i = i > abs > Real.fromInt > Math.sqrt 4

Another example Backup function fun backup1 (f,g) = fn x => case f x of NONE => g x SOME y => y As is often the case with higher-order functions, the types hint at what the function does ('a -> 'b option) * ('a -> 'b) -> 'a -> 'b More examples later to curry and uncurry functions 5

Currying and Partial Application Recall every ML function takes exactly one argument Previously encoded n arguments via one n-tuple Another way: Take one argument and return a function that takes another argument and Called currying after famous logician Haskell Curry Example, with full and partial application: Notice relies on lexical scope val sorted3 = fn x => fn y => fn z => z >= y andalso y >= x val true_ans = ((sorted3 7) 9) 11 val is_non_negative = (sorted3 0) 0 6

Syntactic sugar Currying is much prettier than we have indicated so far Can write e1 e2 e3 e4 in place of ((e1 e2) e3) e4 Can write fun f x y z = e in place of fun f x = fn y => fn z => e fun sorted3 x y z = z >= y andalso y >= x val true_ans = sorted3 7 9 11 val is_non_negative = sorted3 0 0 Result is a little shorter and prettier than the tupled version: fun sorted3 (x,y,z) = z >= y andalso y >= x val true_ans = sorted3(7,9,11) fun is_non_negative x = sorted3(0,0,x) 7

Return to the fold In addition to being sufficient multi-argument functions and pretty, currying is useful because partial application is convenient Example: Often use higher-order functions to create other functions fun fold f acc xs = case xs of [] => acc x::xs => fold f (f(acc,x)) xs fun sum_ok xs = fold (fn (x,y) => x+y) 0 xs val sum_cool = fold (fn (x,y) => x+y) 0 8

The library s way So the SML standard library is fond of currying iterators See types for List.map, List.filter, List.foldl, etc. So calling them as though arguments are tupled won t work Another example is List.exists: fun exists predicate xs = case xs of [] => false x::xs => predicate xs orelse exists predicate xs val no = exists (fn x => x=7) [4,11,23] val has_seven = exists (fn x => x=7) 9

Another example Currying and partial application can be convenient even without higher-order functions fun zip xs ys = case (xs,ys) of ([],[]) => [] (x::xs,y::ys ) => (x,y)::(zip xs ys ) _ => raise Empty fun range i j = if i>j then [] else i :: range (i+1) j val countup = range 1 (* partial application *) fun add_number xs = zip (countup (length xs)) xs 10

More combining functions What if you want to curry a tupled function or vice-versa? What if a function s arguments are in the wrong order for the partial application you want? Naturally, it s easy to write higher-order wrapper functions And their types are neat logical formulas fun other_curry1 f = fn x => fn y => f y x fun other_curry2 f x y = f y x fun curry f x y = f (x,y) fun uncurry f (x,y) = f x y 11

The Value Restriction Appears If you use partial application to create a polymorphic function, it may not work due to the value restriction Warning about type vars not generalized And won t let you call the function This should surprise you; you did nothing wrong but you still must change your code See the written lecture summary about how to work around this wart (and ignore the issue until it arises) The wart is there for good reasons, related to mutation and not breaking the type system More in the lecture on type inference 12

Efficiency So which is faster: tupling or currying multiple-arguments? They are both constant-time operations, so it doesn t matter in most of your code plenty fast Don t program against an implementation until it matters! For the small (zero?) part where efficiency matters: It turns out SML NJ compiles tuples more efficiently But many other functional-language implementations do better with currying (OCaml, F#, Haskell) So currying is the normal thing and programmers read t1 -> t2 -> t3 -> t4 as a 3-argument function 13

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 Fortunately, a function s type does not include the types of bindings in its environment (In OOP, objects and private fields are used similarly, e.g., Java Swing s event-listeners) 14

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 For the reasons we have discussed, ML variables really are immutable, but there are mutable references (use sparingly) New types: t ref where t is a type New expressions: ref e to create a reference with initial contents e e1 := e2 to update contents!e to retrieve contents (not negation) 15

References example val x = ref 42 val y = ref 42 val z = x val _ = x := 43 val w = (!y) + (!z) (* 85 *) (* x + 1 does not type-check) A variable bound to a reference (e.g., x) is still immutable: it will always refer to the same reference But the contents of the reference may change via := And there may be aliases to the reference, which matter a lot Reference are first-class values Like a one-field mutable object, so := and! don t specify the field 16

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. In example, callbacks have type int->unit (executed for side-effect) So the entire public library interface would be the function for registering new callbacks: val onkeyevent : (int -> unit) -> unit 17

Library implementation val cbs : (int -> unit) list ref = ref [] fun onkeyevent f = cbs := f :: (!cbs) fun onevent i = let fun loop fs = case fs of [] => () f::fs => (f i; loop fs ) in loop (!cbs) end 18

Clients Can only register an int -> unit, so if any other data is needed, must be in closure s environment And if need to remember something, need mutable state Examples: val timespressed = ref 0 val _ = onkeyevent (fn _ => timespressed := (!timespressed) + 1) fun printifpressed i = onkeyevent (fn _ => if i=j then print ("pressed " ^ Int.toString i) else ()) 19

Implementing an ADT As our last pattern, closures can implement abstract datatypes Can put multiple functions in a record They can share the same private data Private data can be mutable or immutable (latter preferred?) Feels quite a bit like objects, emphasizing that OOP and functional programming have similarities See lec9.sml for an implementation of immutable integer sets with operations insert, member, and size The actual code is advanced/clever/tricky, but has no new features Combines lexical scope, datatypes, records, closures, etc. Client use is not so tricky 20