Anonymous Functions CMSC 330: Organization of Programming Languages

Similar documents
CMSC 330: Organization of Programming Languages. Closures (Implementing Higher Order Functions)

CMSC 330: Organization of Programming Languages. Closures (Implementing Higher Order Functions)

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

CMSC 330: Organization of Programming Languages. OCaml Higher Order Functions

CMSC 330: Organization of Programming Languages. OCaml Higher Order Functions

CMSC 330: Organization of Programming Languages. OCaml Higher Order Functions

CMSC 631. Functional Programming with OCaml

COMP 150-AVS Fall OCaml and Functional Programming

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

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

Topics Covered Thus Far CMSC 330: Organization of Programming Languages

CMSC 330: Organization of Programming Languages

CMSC 330: Organization of Programming Languages. Lets, Tuples, Records

Topics Covered Thus Far. CMSC 330: Organization of Programming Languages. Language Features Covered Thus Far. Programming Languages Revisited

OCaml Language Choices CMSC 330: Organization of Programming Languages

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

CMSC330. Objects, Functional Programming, and lambda calculus

CMSC 330, Fall 2013, Practice Problem 3 Solutions

CMSC330 Fall 2013 Practice Problems 6 Solutions

CMSC 330: Organization of Programming Languages. OCaml Expressions and Functions

Every language has its own scoping rules. For example, what is the scope of variable j in this Java program?

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. Operational Semantics

Weeks 6&7: Procedures and Parameter Passing

Object-oriented programming. and data-structures CS/ENGRD 2110 SUMMER 2018

Lecture 16: Static Semantics Overview 1

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

COMP 250: Java Programming I. Carlos G. Oliver, Jérôme Waldispühl January 17-18, 2018 Slides adapted from M. Blanchette

CMSC 330: Organization of Programming Languages. Lambda Calculus

Functional Languages. CSE 307 Principles of Programming Languages Stony Brook University

CMSC 330, Fall 2013, Practice Problems 3

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

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

CMSC 430 Introduction to Compilers. Fall Everything (else) you always wanted to know about OCaml (but were afraid to ask)

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

CMSC 330: Organization of Programming Languages. Objects and Functional Programming

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

Semantic Processing. Semantic Errors. Semantics - Part 1. Semantics - Part 1

CMSC330 Spring 2015 Final Exam 9:30am/11:00am/12:30pm

Concepts Introduced in Chapter 7

CMSC 330: Organization of Programming Languages. Lambda Calculus

CS558 Programming Languages. Winter 2013 Lecture 3

CS Programming Languages: Scala

CS 330 Lecture 18. Symbol table. C scope rules. Declarations. Chapter 5 Louden Outline

INDEX. A SIMPLE JAVA PROGRAM Class Declaration The Main Line. The Line Contains Three Keywords The Output Line

Monday Feb 16, 5pm. solve these equalities. Midterm Thursday Feb 12. covers only ocaml part of the course, assignments 1 through 3.

Contents. 8-1 Copyright (c) N. Afshartous

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

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

G Programming Languages - Fall 2012

Back to OCaml. Summary of polymorphism. Example 1. Type inference. Example 2. Example 2. Subtype. Polymorphic types allow us to reuse code.

Functional Programming. Pure Functional Programming

CMSC330 Fall 2015 Midterm #1 12:30pm/2:00pm/5:00pm

CSCE 314 Programming Languages. Type System

INF 102 CONCEPTS OF PROG. LANGS FUNCTIONAL COMPOSITION. Instructors: James Jones Copyright Instructors.

CMSC330 Spring 2016 Midterm #1 9:30am/12:30pm/3:30pm

An introduction to C++ template programming

CSCI-GA Scripting Languages

CMSC330 Fall 2010 Final Exam Solutions

CMSC330 Fall 2016 Midterm #1 2:00pm/3:30pm

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

Chapter 1. Fundamentals of Higher Order Programming

CSE 307: Principles of Programming Languages

CMSC 330: Organization of Programming Languages. OCaml Imperative Programming

Lecture #23: Conversion and Type Inference

Polymorphism. CMSC 330: Organization of Programming Languages. Two Kinds of Polymorphism. Polymorphism Overview. Polymorphism

Names and Types. standard hue names. Dr. Philip Cannata 1

CMSC 330: Organization of Programming Languages

Conversion vs. Subtyping. Lecture #23: Conversion and Type Inference. Integer Conversions. Conversions: Implicit vs. Explicit. Object x = "Hello";

Functions. x y z. f (x, y, z) Take in input arguments (zero or more) Perform some computation - May have side-effects (such as drawing)

INF 212 ANALYSIS OF PROG. LANGS FUNCTION COMPOSITION. Instructors: Crista Lopes Copyright Instructors.

Ruby: Introduction, Basics

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

Names, Scope, and Bindings

Principles of Programming Languages

Lecture Set 4: More About Methods and More About Operators

Lecture Set 4: More About Methods and More About Operators

Parametric types. map: ( a (a b) a list b list. filter: ( a bool) a list a list. Why? a and b are type variables!

Names, Bindings, Scopes

CS Lectures 2-3. Introduction to OCaml. Polyvios Pratikakis

About this exam review

Reflection. Based on

CMSC330 Fall 2014 Midterm 2 Solutions

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

Execution order. main()

Carlos Varela RPI September 19, Adapted with permission from: Seif Haridi KTH Peter Van Roy UCL

Chapter 11 :: Functional Languages

CS 61C: Great Ideas in Computer Architecture Introduction to C

CMSC330 Spring 2016 Midterm #1 9:30am/12:30pm/3:30pm Solution

Functional Programming. Introduction To Cool

Ruby: Introduction, Basics

Static Semantics. Lecture 15. (Notes by P. N. Hilfinger and R. Bodik) 2/29/08 Prof. Hilfinger, CS164 Lecture 15 1

Names, Scope, and Bindings

Programming Language Features. CMSC 330: Organization of Programming Languages. Turing Completeness. Turing Machine.

CMSC 330: Organization of Programming Languages

Functions - Lecture 7. Nested functions. Another example. A Nested Function. Josef Svenningsson

Recap: Functions as first-class values

CHAPTER 4 FUNCTIONS. 4.1 Introduction

So what does studying PL buy me?

Transcription:

Anonymous Functions CMSC 330: Organization of Programming Languages Recall code blocks in Ruby (1..10).each { x print x Here, we can think of { x print x as a function OCaml 2 Higher Order Functions 1 We can do this (and more) in Ocaml where range_each (1,10) (fun x -> print_int x) let rec range_each (i,j) f = if i > j then () else let _ = f i in (* ignore result *) range_each (i+1,j) f 2 Anonymous Functions All Functions Are Anonymous Passing functions around is very common So often we don t want to bother to give them names Use fun to make a function with no name Parameter Body Functions are first-class, so you can bind them to other names as you like let f x = x + 3 let g = f g 5 = 8 (fun x -> x + 3) 5 fun x -> x + 3 = 8 In fact, let for functions is just shorthand let f x = body stands for let f = fun x -> body 3 4

Examples let next x = x + 1 Short for let next = fun x -> x + 1 Higher-Order Functions In OCaml you can pass functions as arguments, and return functions as results let plus (x, y) = x + y Short for let plus = fun (x, y) -> x + y Which is short for! let plus = fun z -> (match z with (x, y) -> x + y) let rec fact n = if n = 0 then 1 else n * fact (n-1) Short for let rec fact = fun n -> (if n = 0 then 1 else n * fact (n-1)) let plus_three x = x + 3 let twice f z = f (f z) twice plus_three 5 twice : ('a->'a) -> 'a -> 'a let plus_four x = x + 4 let pick_fn n = if n > 0 then plus_three else plus_four (pick_fn 5) 0 pick_fn : int -> (int->int) 5 6 Currying Curried Functions In OCaml We just saw a way for a function to take multiple arguments The function consumes one argument at a time, returning a function that takes the rest This is called currying the function Named after the logician Haskell B. Curry But Schönfinkel and Frege discovered it! So it should probably be called Schönfinkelizing or Fregging OCaml has a really simple syntax for currying This is identical to all of the following: 7 8 Thus: let add x y = x + y let add = (fun x -> (fun y -> x + y)) let add = (fun x y -> x + y) let add x = (fun y -> x+y) add has type int -> (int -> int) add 3 has type int -> int! add 3 is a function that adds 3 to its argument (add 3) 4 = 7 This works for any number of arguments

Curried Functions In OCaml (cont.) Because currying is so common, OCaml uses the following conventions: -> associates to the right! Thus int -> int -> int is the same as! int -> (int -> int) function application associates to the left! Thus add 3 4 is the same as! (add 3) 4 Mental Shorthand You can think of curried types as defining multiargument functions Type int -> float -> float is a function that takes an int and a float and returns a float Type int -> int -> int -> int is a function that takes three ints and returns an int The bonus is that you can partially apply the function to some of its arguments And apply that to the rest of the arguments later 9 10 Another Example Of Currying A curried add function with three arguments: The same as Then... add_th has type int -> (int -> (int -> int)) add_th 4 has type int -> (int -> int) add_th 4 5 has type int -> int add_th 4 5 6 is 15 let add_th x y z = x + y + z let add_th x = (fun y -> (fun z -> x+y+z)) Implementing this is Challenging! Implementing functions that return other functions requires a clever data structure called a closure We ll see how these are implemented later In the meantime, we will explore using higher order functions, and then discuss how they are implemented 11 12

The Map Function Let s write the map function (like Ruby's collect) Takes a function and a list, applies the function to each element of the list, and returns a list of the results let rec map f l = match l with [] -> [] (h::t) -> (f h)::(map f t) let add_one x = x + 1 let negate x = -x map add_one [1; 2; 3] map negate [9; -5; 0] Type of map? The Map Function (cont.) What is the type of the map function? let rec map f l = match l with [] -> [] (h::t) -> (f h)::(map f t) ('a -> 'b) -> 'a list -> 'b list f l 13 14 Pattern Matching With Fun match can be used within fun map (fun l -> match l with (h::_) -> h) [ [1; 2; 3]; [4; 5; 6; 7]; [8; 9] ] = [1; 4; 8] But use named functions for complicated matches May use standard pattern matching abbreviations map (fun (x, y) -> x+y) [(1,2); (3,4)] = [3; 7] 15 The Fold Function Common pattern Iterate through list and apply function to each element, keeping track of partial results computed so far let rec fold f a l = match l with [] -> a (h::t) -> fold f (f a h) t a = accumulator Usually called fold left to remind us that f takes the accumulator as its first argument What's the type of fold? = ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a 16

Example Another Example let rec fold f a l = match l with [] -> a (h::t) -> fold f (f a h) t let rec fold f a l = match l with [] -> a (h::t) -> fold f (f a h) t let add a x = a + x fold add 0 [1; 2; 3; 4] fold add 1 [2; 3; 4] fold add 3 [3; 4] fold add 6 [4] fold add 10 [] 10 let next a _ = a + 1 fold next 0 [2; 3; 4; 5] fold next 1 [3; 4; 5] fold next 2 [4; 5] fold next 3 [5] fold next 4 [] 4 We just built the sum function! We just built the length function! 17 18 Using Fold to Build Reverse Currying Is Standard In OCaml let rec fold f a l = match l with [] -> a (h::t) -> fold f (f a h) t Can you build the reverse function with fold? let prep a x = x::a fold prep [] [1; 2; 3; 4] fold prep [1] [2; 3; 4] fold prep [2; 1] [3; 4] fold prep [3; 2; 1] [4] fold prep [4; 3; 2; 1] [] [4; 3; 2; 1] Pretty much all functions are curried Like the standard library map, fold, etc. See /usr/local/ocaml/lib/ocaml on Grace! In particular, look at the file list.ml for standard list functions! Access these functions using List.<fn name>! E.g., List.hd, List.length, List.map OCaml works hard to make currying efficient Otherwise it would do a lot of useless allocation of closures (which we see later) when all arguments are provided 19 20

A Convention Since functions are curried, function can often be used instead of match function declares an anonymous function of one argument Instead of let rec sum l = match l with [] -> 0 (h::t) -> h + (sum t) It could be written A Convention (cont.) Instead of let rec map f l = match l with [] -> [] (h::t) -> (f h)::(map f t) It could be written let rec map f = function [] -> [] (h::t) -> (f h)::(map f t) let rec sum = function [] -> 0 (h::t) -> h + (sum t) 21 22 Nested Functions In OCaml, you can define functions anywhere Even inside of other functions Nested Functions (cont.) You can also use let to define functions inside of other functions let sum l = fold (fun a x -> a + x) 0 l let sum l = let add a x = a + x in fold add 0 l let pick_one n = if n > 0 then (fun x -> x + 1) else (fun x -> x - 1) (pick_one -5) 6 (* returns 5 *) let pick_one n = let add_one x = x + 1 in let sub_one x = x - 1 in if n > 0 then add_one else sub_one 23 24

How About This? let addn n l = let add x = n + x in map add l (Equivalent to...) let addn n l = map (fun x -> n + x) l Accessing variable from outer scope Returned Functions In OCaml a function can return another function as a result; this is what currying is doing Consider the following example let addn n = (fun x -> x + n) (addn 3) 4 (* returns 7 *) When the anonymous function is called, n isn t even on the stack any more!! We need some way to keep n around after addn returns 25 26 The Call Stack in C/Java/etc. Now Consider Returning Functions void f(void) { int x; x = g(3); int g(int x) { int y; y = h(x); return y; int h (int z) { return z + 1; int main(){ f(); return 0; x <junk> 4 x 3 y <junk> 4 z 3 f g h let map f n = match n with [] -> [] (h::t) -> (f h)::(map f t) let addn n l = let add x = n + x in map add l addn 3 [1; 2; 3] n 3 Uh oh...how does add know the value of n? OCaml does not read it off the stack! The language could do this, but can be confusing (see above) OCaml uses static scoping like C, C++, Java, and Ruby 27 28 l f n x 1 <list> <add>

Static Scoping (aka Lexical Scoping) In static or lexical scoping, (nonlocal) names refer to their nearest binding in the program text Going from inner to outer scope In our example, add refers to addn s n C example: Refers to the x at file scope that s the nearest x going from inner scope to outer scope in the source code int x; void f() { x = 3; void g() { char *x = "hello"; f(); Closures Implement Static Scoping An environment is a mapping from variable names to values Just like a stack frame A closure is a pair (f, e) consisting of function code f and an environment e When you invoke a closure, f is evaluated using e to look up variable bindings 29 30 Example Closure 1 let add x = (fun y -> x + y) Example Closure 2 let mult_sum (x, y) = let z = x + y in fun w -> w * z (add 3) 4 <cl> 4 3 + 4 7 (mult_sum (3, 4)) 5 <cl> 5 5 * 7 35 Closure Function Environment 31 32

Example Closure 3 let twice (n, y) = let f x = x + n in f (f y) twice (3, 4) <cl> (<cl> 4) <cl> 7 10 Example Closure 4 let add x = (fun y -> (fun z -> x + y + z)) add( ) took 3 arguments? The compiler figures this out and avoids making closures (((add 1) 2) 3) ((<cl> 2) 3) (<cl> 3) 1+2+3 33 34 Higher-Order Functions in C C supports function pointers typedef int (*int_func)(int); void app(int_func f, int *a, int n) { for (int i = 0; i < n; i++) a[i] = f(a[i]); int add_one(int x) { return x + 1; int main() { int a[] = {5, 6, 7; app(add_one, a, 3); 35 Higher-Order Functions in C (cont.) C does not support closures Since no nested functions allowed Unbound symbols always in global scope int y = 1; void app(int(*f)(int), n) { return f(n); int add_y(int x) { return x + y; int main() { app(add_y, 2); 36

Higher-Order Functions in C (cont.) Cannot access non-local variables in C OCaml code let add x y = x + y Equivalent code in C is illegal int (* add(int x))(int) { return add_y; int add_y(int y) { return x + y; // x undefined Higher-Order Functions in C (cont.) OCaml code let add x y = x + y Works if C supports nested functions Not in ISO C, but in gcc; but not allowed to return them int (* add(int x))(int) { int add_y(int y) { return x + y; return add_y; Does not allocate closure, so x popped from stack and add_y will get garbage (potentially) when called 37 38 Higher-Order Functions in Ruby Ruby supports higher-order functions Use yield within method to call code block argument def my_collect(a) b = Array.new(a.length) 0.upto(a.length-1) { i b[i] = yield(a[i]) return b b = my_collect([5, 6, 7]) { x x+1 39 Higher-Order Functions in Ruby (cont.) Ruby supports closures Code blocks can access non-local variables Binding determined by lexical scoping def twice yield yield x = 1 twice {x += 1 puts x # 3 def twice x = 0 #dynamic yield yield x = 1 #lexical twice {x += 1 puts x # 3 not 1 40

Higher-Order Functions in Ruby (cont.) Ruby code blocks are actual variables def twice # implicit block yield # invoked with yield yield twice { x += 1 # same as x += 2 def quad (&block) # explicit block twice (&block) # used as argument twice (&block) quad { x += 1 # same as x += 4 Higher-Order Functions in Ruby (cont.) Code blocks may be saved def quad (&block) # explicit block c = block # no ampersand! twice (c) # used as argument twice (c) def twice c # arg = explicit closure c.call # invoke with.call c.call quad { x += 1 # same as x += 4 41 42 Higher-Order Functions in Ruby (cont.) Ruby supports creating closures directly Proc.new c1 = Proc.new { x+=1 proc c2 = proc { x+=1 lambda c3 = lambda { x+=1 method def foo x+=1 c4 = method { :foo c.call # x+=1 Higher-Order Functions in Java/C++ An object in Java or C++ is kind of like a closure It has some data (like an environment) Along with some methods (i.e., function code) So objects can be used to simulate closures So is an anonymous Java inner class Inner class methods can access fields of outer class Back in CMSC 132 (OOP II) We studied how to implement some functional patterns in OO languages 43 44

Java 8 Supports Lambda Expressions Ocaml s function (a, b) -> a + b Is like the following in Java 8 (a, b) -> a + b Java 8 supports closures, and variations on this syntax 45 Java 8 Example public class Calculator { interface IntegerMath { int operation(int a, int b); public int operatebinary(int a, int b, IntegerMath op) { return op.operation(a, b); public static void main(string... args) { Calculator myapp = new Calculator(); IntegerMath addition = (a, b) -> a + b; IntegerMath subtraction = (a, b) -> a - b; System.out.println("40 + 2 = " + myapp.operatebinary(40, 2, addition)); System.out.println("20-10 = " + myapp.operatebinary(20, 10, subtraction)); Lambda expressions 46