Functions & First Class Function Values

Similar documents
Bindings & Substitution

Environments

Higher-Order Functions (Part I)

Higher-Order Functions

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

An Introduction to Functions

CS 360 Programming Languages Interpreters

A Third Look At ML. Chapter Nine Modern Programming Languages, 2nd ed. 1

6.184 Lecture 4. Interpretation. Tweaked by Ben Vandiver Compiled by Mike Phillips Original material by Eric Grimson

CMSC 330: Organization of Programming Languages

Interpreters. Prof. Clarkson Fall Today s music: Step by Step by New Kids on the Block

6.037 Lecture 4. Interpretation. What is an interpreter? Why do we need an interpreter? Stages of an interpreter. Role of each part of the interpreter

CSE341, Spring 2013, Final Examination June 13, 2013

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

Functional abstraction. What is abstraction? Eating apples. Readings: HtDP, sections Language level: Intermediate Student With Lambda

Functional abstraction

Functional Programming. Pure Functional Programming

CS115 - Module 9 - filter, map, and friends

Programming Languages

Recap: Functions as first-class values

CS 314 Principles of Programming Languages

LECTURE 16. Functional Programming

The syntax and semantics of Beginning Student

The syntax and semantics of Beginning Student

Comp 311: Sample Midterm Examination

Principles of Programming Languages 2017W, Functional Programming

Lecture 2: Big-Step Semantics

Project 2: Scheme Interpreter

CS115 - Module 10 - General Trees

Procedures. EOPL3: Section 3.3 PROC and App B: SLLGEN

Fall Semester, The Metacircular Evaluator. Today we shift perspective from that of a user of computer langugaes to that of a designer of

Variables. Substitution

Recap: ML s Holy Trinity

CSE341: Programming Languages Lecture 17 Implementing Languages Including Closures. Dan Grossman Autumn 2018

The Substitution Model

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

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

Scheme as implemented by Racket

CMPT 379 Compilers. Parse trees

CMSC 330: Organization of Programming Languages. Operational Semantics

Introduction to Functional Programming in Haskell 1 / 56

CS61A Midterm 2 Review (v1.1)

Lecture 09: Data Abstraction ++ Parsing is the process of translating a sequence of characters (a string) into an abstract syntax tree.

Recap: ML s Holy Trinity. Story So Far... CSE 130 Programming Languages. Datatypes. A function is a value! Next: functions, but remember.

Module 8: Local and functional abstraction

CSE 130 Programming Languages. Datatypes. Ranjit Jhala UC San Diego

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

The Environment Model

Module 10: Imperative Programming, Modularization, and The Future

The Environment Model. Nate Foster Spring 2018

Lecture 12: Conditional Expressions and Local Binding

Principles of Programming Languages

CS 314 Principles of Programming Languages. Lecture 16

CSE341 Spring 2017, Final Examination June 8, 2017

Ruby: Introduction, Basics

CSE 130 Programming Languages. Lecture 3: Datatypes. Ranjit Jhala UC San Diego

CSE 341 Section 7. Ethan Shea Autumn Adapted from slides by Nicholas Shahan, Dan Grossman, Tam Dang, and Eric Mullen

Languages as Libraries

CSE 130 [Winter 2014] Programming Languages

Compiler Construction Lecture 05 A Simple Stack Machine. Lent Term, Lecturer: Timothy G. Griffin. Computer Laboratory University of Cambridge

Concepts of programming languages

Lecture 13 CIS 341: COMPILERS

Compilers. Type checking. Yannis Smaragdakis, U. Athens (original slides by Sam

1 Lexical Considerations

The Substitution Model. Nate Foster Spring 2018

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

Syntax and Grammars 1 / 21

Operators and Expressions:

B The SLLGEN Parsing System

CSCC24 Functional Programming Scheme Part 2

An Explicit-Continuation Metacircular Evaluator

Lexical and Syntax Analysis

Formal Semantics. Prof. Clarkson Fall Today s music: Down to Earth by Peter Gabriel from the WALL-E soundtrack

Ways to implement a language

Recap. Recap. If-then-else expressions. If-then-else expressions. If-then-else expressions. If-then-else expressions

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

COS 320. Compiling Techniques

Name EID. (calc (parse '{+ {with {x {+ 5 5}} {with {y {- x 3}} {+ y y} } } z } ) )

CSE 341: Programming Languages

CSE 505, Fall 2008, Final Examination 11 December Please do not turn the page until everyone is ready.

A LISP Interpreter in ML

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

OCaml Style Guide Fall 2017

CSE341 Autumn 2017, Final Examination December 12, 2017

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

Understanding Recursion

Lecture #13: Type Inference and Unification. Typing In the Language ML. Type Inference. Doing Type Inference

More Examples. Lecture 24: More Scala. Higher-Order Functions. Control Structures

Organization of Programming Languages CS3200/5200N. Lecture 11

Type Soundness. Type soundness is a theorem of the form If e : τ, then running e never produces an error

CSE341 Spring 2017, Final Examination June 8, 2017

Programming Languages

Overview. Elements of Programming Languages. Evaluation order. Evaluation order

Programming Languages

Space War Class Diagram. Elements of OOP. How to design interactions between objects. Space War Class Diagram with Inheritance

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

Final CSE 131B Spring 2004

A Small Interpreted Language

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

Administrivia. Simple data types

Transcription:

Functions & First Class Function Values PLAI 1st ed Chapter 4, PLAI 2ed Chapter 5 The concept of a function is itself very close to substitution, and to our with form. Consider the following morph 1 { with {x 5} {* x x}} { with {x} {* x x}} { fun {x} {* x x}}

Functions & First Class Function Values 2017-03-02 PLAI 1st ed Chapter 4, PLAI 2ed Chapter 5 The concept of a function is itself very close to substitution, and to our with form. Consider the following morph 1 { with {x 5} {* x x}} { with {x} {* x x}} { fun {x} {* x x}} 1. Now that we have a form for local bindings, which forced us to deal with proper substitutions and everything that is related, we can get to functions.

As with the with expression, we also need a form to use these functions. We can use call for this, so we want: 2 { call { fun {x} {* x x}} 5} to be the same as the original thing we started with 3 { with {x 5} {* x x}}

So far, all we get is more verbose local bindings What we re really missing is a way to name these functions. 4 { with { sqr { fun {x} {* x x }}} {+ { call sqr 5} { call sqr 6}}} Here we say that x is the formal parameter (or argument), and the 5 and 6 are actual parameters.

So far, all we get is more verbose local bindings 2017-03-02 What we re really missing is a way to name these functions. 4 { with { sqr { fun {x} {* x x }}} {+ { call sqr 5} { call sqr 6}}} Here we say that x is the formal parameter (or argument), and the 5 and 6 are actual parameters. 1. Note that this way of binding functions depends strongly on our functions being values.

Implementing First Class Function Values PLAI Chapter 6 (uses some stuff from ch. 5, which we do later) Three basic approaches to functions/procedures First order: functions are not values. E.g. Java methods. Higher order: functions can receive and return other functions as values. This is what you get in C. First class: functions are values with all the rights of other values.

Implementing First Class Function Values 2017-03-02 PLAI Chapter 6 (uses some stuff from ch. 5, which we do later) Three basic approaches to functions/procedures First order: functions are not values. E.g. Java methods. Higher order: functions can receive and return other functions as values. This is what you get in C. First class: functions are values with all the rights of other values. 1. They cannot be used or returned as values by other functions. This means that they cannot be stored in data values. 2. In particular, they can be supplied to other functions, returned from functions, stored in data structures, and new functions can be created at run-time.

In machine-code, to compute an expression such as 5 (-b + sqrt (b^2-4* a*c )) / 2a you have to do something like this: 6 x = b * b y = 4 * a y = y * c x = x - y x = sqrt (x) y = -b x = y + x y = 2 * a s = x / y

In high-level programming languages you can just write the original expression, with no names for these values. With first-class functions, complex expressions can have functions as intermediate values. 7 ( map ( lambda (x) (+ x 3)) ( list 1 2 3)) fun generates a function, and we can choose to either bind it to a name, or not. This has a major effect on the personality and expressive power of a programming language as we will see.

Lambda is not the main issue The following is working JavaScript code, that uses first class functions. 8 function foo (x) { function bar (y) { return x + y; } return bar ; } function main () { var f = foo (1) ; var g = foo (10) ; console.log (" >> "+ f (2) + ", " + g (2) ); }

Equivalent Racket code, no explicit lambda 9 ( define ( foo x) ( local [( define ( bar y) (+ x y))] bar )) The returned function is not anonymous, but it s not really named either: the bar name is bound only inside the body of foo, and outside of it that name is irrelevant.

GCC includes extensions that allow internal function definitions, but it still does not have first class functions trying to do the above is broken: 10 # include < stdio.h > typedef int (* int2int )( int ); int2int foo ( int x) { int bar ( int y) { return x + y; } return bar ; } int main () { int2int f = foo (1) ; int2int g = foo ( 10) ; printf (" >> %d, %d\n", f (2), g (2) ); }

The FLANG Language Now for the implementation we call this new language FLANG. First, the BNF: 11 flang : NUMBER { + flang flang } { - flang flang } { * flang flang } { / flang flang } { WITH { ID flang } flang } ID { FUN { ID } flang } { CALL flang flang }

And the matching type definition: 12 ( define- type FLANG [ Num ( val : number )] [ Add (l : FLANG ) (r : FLANG )] [ Sub (l : FLANG ) (r : FLANG )] [ Mul (l : FLANG ) (r : FLANG )] [ Div (l : FLANG ) (r : FLANG )] [Id ( name : symbol )] [ With ( id : symbol ) ( named- expr : FLANG ) ( bound-body : FLANG )] [ Fun ( param : symbol ) ( body : FLANG )] [ Call ( fun : FLANG ) ( val : FLANG )]) ; first type!

The parser is pretty much cut-paste-and-munge from WAE 13. [( s-exp-match? '( fun ( SYMBOL ) ANY ) sx) ( let* ([ args ( sx-ref sx 1)] [id ( s-exp- > symbol ( sx-ref args 0))] [ body ( parse-sx ( sx-ref sx 2))]) ( Fun id body ))] [( s-exp-list? sx) ( let* ([l (λ () ( parse-sx ( sx-ref sx 1)))] [r (λ () ( parse-sx ( sx-ref sx 2)))]) ( case ( s-exp- > symbol ( sx-ref sx 0)).. [( call ) ( Call (l) (r))]

We also need to patch up the substitution function to deal with fun and call. Mostly it is the same: 14 N[ v/x ] = N {+ E1 E2 }[ v/x ] = {+ E1[v/x ] E2[v/x ]} ;; -, *, /... y[ v/x ] = y x[ v/x ] = v { with {y E1} E2 }[ v/x ] = { with {y E1[v/x ]} E2[v/x ]} { with {x E1} E2 }[ v/x ] = { with {x E1[v/x ]} E2}

The new part: call looks like arithmetic, fun looks like with. 15 { call E1 E2 }[ v/x ] = { call E1[v/x ] E2[v/x ]} 16 { fun {y} E}[ v/x ] = { fun {y} E[ v/x ]} { fun {x} E}[ v/x ] = { fun {x} E}

And the matching code: 17 ( type- case FLANG expr. [ Call (l r) ( Call ( subst l from to) ( subst r from to))] [ Fun ( bound-id bound-body ) (if (eq? bound-id from ) expr ( Fun bound- id ( subst bound- body from to)))]))

we need to decide on how to represent values in FLANG. Before, we had only numbers and we used (Racket) numbers to represent them. What should be the result of evaluating 18 { fun {x} {+ x 1}} We need some way, e.g. type variants to distinguish between functions and numbers. In fact we already have a type which would work, namely FLANG We could also define a result type, which might be a bit cleaner, but the main issues are the same.

Use FLANG to represent values means that evaluating: 19 ( Add ( Num 1) ( Num 2)) now yields ( Num 3) and `( Num 5) ' evaluates to `( Num 5) '. In a similar way, 20 ( Fun 'x ( Num 2)) evaluates to ( Fun 'x ( Num 2))

The formal evaluation rules treat functions like numbers, and use the syntax object to represent both values: 21 eval (N) = N eval ({+ E1 E2 }) = eval (E1) + eval (E2) eval ({- E1 E2 }) = eval (E1) - eval (E2) eval ({* E1 E2 }) = eval (E1) * eval (E2) eval ({/ E1 E2 }) = eval (E1) / eval (E2)

The formal evaluation rules treat functions like numbers, and 2017-03-02 use the syntax object to represent both values: 21 eval (N) = N eval ({+ E1 E2 }) = eval (E1) + eval (E2) eval ({- E1 E2 }) = eval (E1) - eval (E2) eval ({* E1 E2 }) = eval (E1) * eval (E2) eval ({/ E1 E2 }) = eval (E1) / eval (E2) 1. call will be very similar to with the only difference is that its arguments are ordered a little differently, being retrieved from the function that is applied and the argument.

22 eval ( id) = error! eval ({ with {x E1} E2 }) = eval (E2[ eval (E1)/x]) eval ( FUN ) = FUN ; assuming FUN ; is a function expression eval ({ call E1 E2 }) = if eval (E1) = { fun {x} Ef} eval (Ef[ eval (E2)/x]) else error!

Note that the call rule could be written using a translation to a with expression: 23 eval ({ call E1 E2 }) = if eval (E1) = { fun {x} Ef} then eval ({ with {x E2} Ef }) else error! Symmetrically, we could specify with using call and fun : 24 eval ({ with {x E1} E2 }) = eval ({ call { fun {x} E2} E1 })

we now have two kinds of values, so we need to check the arithmetic operation s arguments too: 25 eval ({+ E1 E2 }) = eval (E1) + eval (E2) if eval (E1) and eval (E2) are numbers otherwise error!...

The FLANG evaluator looks like: 26 [ Num ( n) expr ] ; <- change here. [ With ( bound- id named- expr bound- body ) ( eval ( subst bound- body bound- id ( eval named-expr )))] ; <- no `( Num...) '. [ Fun ( bound- id bound- body ) expr ] ; <- like `Num ' [ Call ( fun arg-expr ) ( type- case FLANG fun [ Fun ( bound- id bound- body ) ; like `With ` ( eval ( subst bound- body bound- id ( eval arg-expr )))] [ else ( error 'eval " not a function ")]) ]))

The arith-op function is in charge of checking that the input values are FLANG numbers, translating them to plain numbers, performing the Racket operation, then re-wrapping the result in a Num. 27 ( define ( arith- op op expr1 expr2 ) ( local [( define (Num- > number e) ( type- case FLANG e [ Num (n) n] [ else ( error ' arith-op " non-number ")]))] ( Num (op (Num- > number expr1 ) (Num- > number expr2 )))))

We can also make things a little easier to use if we make run convert the result to a number: 28 ( define ( run sx) ( let ([ result ( eval ( parse-sx sx))]) ( type- case FLANG result [ Num (n) n] [ else ( error 'run " returned a non-number ")])))

It s alive? 29 ( test ( run '{ call { fun {x} {+ x 1}} 4}) 5) ( test ( run '{ with { add3 { fun {x} {+ x 3}}} { call add3 1}}) 4) ( test ( run '{ with { add3 { fun {x} {+ x 3}}} { with { add1 { fun {x} {+ x 1}}} { with {x 3} { call add1 { call add3 x }}}}}) 7)

Oops, I an evaluation. 30 ( test ( run '{ with { identity { fun {x} x}} { with { foo { fun {x} {+ x 1}}} { call { call identity foo } 123}}}) 124) ( test ( run '{ call { call { fun {x} { call x 1}} { fun {x} { fun {y} {+ x y }}}} 123} ) 124)

Fixing call We just worked through an implementation of first class functions in WAE. But it had a few failing tests. It seems like our call implementation needs work 31 ( run '{ with { identity { fun {x} x}} { with { foo { fun {x} {+ x 1}}} { call { call identity foo } 123}}}) ( run '{ call { call { fun {x} { call x 1}} { fun {x} { fun {y} {+ x y }}}} 123})

So we have to reduce the expression in the function position before we can tell if it is a function. 32 [ Call ( fun arg-expr ) ( let [( funv ( eval fun ))] ( type- case FLANG funv [ Fun ( bound-id bound-body ) ; just like ` with ' ( eval ( subst bound- body bound- id ( eval arg-expr )))] [ else ( error 'eval " expected function ")]))]))

Now our tests pass 33 ( trace eval ) ( test ( run '{ with { identity { fun {x} x}} { with { foo { fun {x} {+ x 1}}} { call { call identity foo } 123}}}) 124) ( test ( run '{ call { call { fun {x} { call x 1}} { fun {x} { fun {y} {+ x y }}}} 123}) 124)