CPS Conversion. Di Zhao.

Similar documents
Compilers: The goal. Safe. e : ASM

A quick introduction to SML

Lists. Michael P. Fourman. February 2, 2010

Programming Language Concepts: Lecture 19

CMSC 330: Organization of Programming Languages. Operational Semantics

Continuations and Continuation-Passing Style

Compiling with Continuations, Continued

1.3. Conditional expressions To express case distinctions like

Last class. CS Principles of Programming Languages. Introduction. Outline

Functional Programming

Type Systems. Today. 1. Organizational Matters. 1. Organizational Matters. Lecture 1 Oct. 20th, 2004 Sebastian Maneth. 1. Organizational Matters

Handout 2 August 25, 2008

Begin at the beginning

Programming Languages Lecture 15: Recursive Types & Subtyping

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

CS422 - Programming Language Design

All the operations used in the expression are over integers. a takes a pair as argument. (a pair is also a tuple, or more specifically, a 2-tuple)

Accurate Step Counting

Lecture 15 CIS 341: COMPILERS

CSCI-GA Scripting Languages

Lecture 2: SML Basics

Verification of an ML compiler. Lecture 3: Closures, closure conversion and call optimisations

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

CSE-321 Programming Languages 2010 Final

G Programming Languages - Fall 2012

Flang typechecker Due: February 27, 2015

(Refer Slide Time: 4:00)

Introduction. chapter Functions

Introduction to the Lambda Calculus

Homework 3 COSE212, Fall 2018

A First Look at ML. Chapter Five Modern Programming Languages, 2nd ed. 1

Types and Programming Languages. Lecture 5. Extensions of simple types

CSE-321 Programming Languages 2012 Midterm

Lecture 13 CIS 341: COMPILERS

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

The University of Nottingham SCHOOL OF COMPUTER SCIENCE A LEVEL 4 MODULE, SPRING SEMESTER MATHEMATICAL FOUNDATIONS OF PROGRAMMING ANSWERS

Polymorphism and Type Inference

5. Introduction to the Lambda Calculus. Oscar Nierstrasz

Typed Scheme: Scheme with Static Types

Haskell 98 in short! CPSC 449 Principles of Programming Languages

Principles of Programming Languages COMP251: Functional Programming in Scheme (and LISP)

Lecture Notes: Control Flow Analysis for Functional Languages

More Lambda Calculus and Intro to Type Systems

9/23/2014. Why study? Lambda calculus. Church Rosser theorem Completeness of Lambda Calculus: Turing Complete

COSE212: Programming Languages. Lecture 3 Functional Programming in OCaml

Formal Systems and their Applications

Theorem Proving Principles, Techniques, Applications Recursion

CS 4110 Programming Languages & Logics. Lecture 28 Recursive Types

Type Systems Winter Semester 2006

Lecture 9: More Lambda Calculus / Types

- M ::= v (M M) λv. M - Impure versions add constants, but not necessary! - Turing-complete. - true = λ u. λ v. u. - false = λ u. λ v.

Programming Languages

PROGRAMMING IN HASKELL. Chapter 2 - First Steps

Fundamentals of Artificial Intelligence COMP221: Functional Programming in Scheme (and LISP)

CIS24 Project #3. Student Name: Chun Chung Cheung Course Section: SA Date: 4/28/2003 Professor: Kopec. Subject: Functional Programming Language (ML)

11/6/17. Outline. FP Foundations, Scheme. Imperative Languages. Functional Programming. Mathematical Foundations. Mathematical Foundations

CHAPTER ONE OVERVIEW. 1.1 Continuation-passing style

Polymorphism and Type Inference

Programming Languages Lecture 14: Sum, Product, Recursive Types

M. Snyder, George Mason University LAMBDA CALCULUS. (untyped)

Functional Programming. Pure Functional Programming

Tail Recursion: Factorial. Begin at the beginning. How does it execute? Tail recursion. Tail recursive factorial. Tail recursive factorial

Mutable References. Chapter 1

CS 6110 S14 Lecture 1 Introduction 24 January 2014

Metaprogramming assignment 3

CMSC 336: Type Systems for Programming Languages Lecture 4: Programming in the Lambda Calculus Acar & Ahmed 22 January 2008.

Functional Programming. Big Picture. Design of Programming Languages

SSA, CPS, ANF: THREE APPROACHES

Lecture #23: Conversion and Type Inference

Organization of Programming Languages CS3200/5200N. Lecture 11

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

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

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

Control in Sequential Languages

CSE-321 Programming Languages 2010 Midterm

CMSC 330: Organization of Programming Languages. Formal Semantics of a Prog. Lang. Specifying Syntax, Semantics

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

Type Checking and Type Inference

Chapter 13: Reference. Why reference Typing Evaluation Store Typings Safety Notes

CIS 500 Software Foundations Fall September 25

More Lambda Calculus and Intro to Type Systems

G Programming Languages - Fall 2012

SML A F unctional Functional Language Language Lecture 19

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

Introduction to ML. Based on materials by Vitaly Shmatikov. General-purpose, non-c-like, non-oo language. Related languages: Haskell, Ocaml, F#,

Lambda Calculus. Lecture 4 CS /26/10

CSE 341: Programming Languages

Datatype declarations

Shell CSCE 314 TAMU. Haskell Functions

Lecture Notes on Data Representation

Lambda Calculus see notes on Lambda Calculus

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

User-defined Functions. Conditional Expressions in Scheme

Recursive Definitions, Fixed Points and the Combinator

MPRI course 2-4 Functional programming languages Exercises

CSE 341, Spring 2011, Final Examination 9 June Please do not turn the page until everyone is ready.

CMSC330. Objects, Functional Programming, and lambda calculus

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

Data Types The ML Type System

Chapter 11 :: Functional Languages

Transcription:

CPS Conversion Di Zhao zhaodi01@mail.ustc.edu.cn This is the first assignment of the course - Advanced Topics in Software Technologies in the 2014-2015 academic year. During this course, we will explore the techniques in functional language compilation. You are required to finish the implementation of the Monkey Compiler for the simplified ML language. Within the procedure (hopefully, if you work hard), you will gain deep understanding of compilation techniques and programming languages. In this assignment, we will introduce the Continuation-Passing Style (CPS), which is a program notation that makes every aspect of control flow and data flow explicit. First, you need to get familiar with our source language: the simplified ML language, and then the syntax of the continuation-passing language - our target language in lab1. Finally, you will finish the code for CPS conversion to translate the expressions of the source language into ones of the target language. 1 ML Syntax Our source language is a subset of the Standard ML (SML) - a language from the ML family. SML is a functional programming language with compile-time type checking and type inference, garbage collection, exception handling and some other features. ML is functional in that functions can be passed as arguments, stored in data structures, and returned as results of function calls. Functions can be statically nested within other functions. Computation in ML is driven by evaluation of expressions, rather than execution of commands, as in imperative languages such as C or Java. For more details, refer to book Programming in Standard ML or http://www.smlnj.org/. Figure 1 illustrates the syntax of our source language - a subset of ML. Here we use the metavariable e to represent an arbitrary expression of the source language. Similarly, x is a metavariable ranging over variables. To be more detailed, for example, fn x => e stands for the abstraction λx.e of the lambda-calculus, in which the body e in turn is another expression. Then we have the application expression e 1 e 2 which means replacing the argument in the body of abstraction e 1 with e 2. (e 1, e 2,..., e n ) is a tuple with n components. Note that in the ML language, n must be no less than 2. #i e represents the projection operation that selects 1

e x variable () empty i integer s string fn x => e abstraction e 1 e 2 application (e 1, e 2,..., e n ) tuple #i e projection ini e tagged value case e of in1 x 1 => e 1 in2 x 2 => e 2 case P rimop e primitive let val x = e 1 in e 2 end let if0 e then e 1 else e 2 if0 let fix f x = e 1 in e 2 end fix P rimop + add sub times print print int2string tostring Figure 1: ML Syntax the ith component of e. Here e should be a tuple. We will not concern about type checking for now. ini e is a tagged value, that append a tag i to the expression e. The case expression: case e of in1 x 1 => e 1 in2 x 2 => e 2, will be evaluated to the result of expression e 1 or e 2 according to the specific tag in expression e, namely, here e should be a tagged value. P rimop e represents a primitive operation of expressions, within which e stands for a list of expressions. For example, print performs on a single expression, so a print expression will be: print [e]. Similarly, a sub expression will be: - [e 1, e 2 ], which means e 1 e 2. if0 e then e 1 else e 2 is a branch expression. If e evaluates to 0, then the if0 expression will be evaluated to the evaluation result of e 1, else to the result of e 2. e 1 and e 2 should be of the same type. let fix f x = e 1 in e 2 end is a fix expression that defines a recursive function f with an argument x and function body e 1 in the expression e 2. f is recursive in that it can appear in e 1 as a free variable. To help printing the numeric result, int2string operation takes an integer and returns a corresponding string. For example, int2string 4 is evaluated to 4. () stands for the constant value of Empty. i stands for a constant integer, s is a constant string value. If you are confused with the syntax, Chapter 3 and 5 of the book Types and Programming Languages or Programming in Standard ML should be helpful. 2

Exercise 1. Finish the code in file ml-ast.sml for the function dumpt that print the ML expression to a text file. Before you start, make sure that you understand the datatype definition in file ml-ast.sml and file ml-ast.sig. Once you re done with this task, the text printed should be a legal function that can be executed in SML/NJ. 2 CPS Syntax Continuation-passing style (CPS) is a program notation that makes every aspect of control flow and data flow explicit. It also has the advantage that it s closely related to Church s lambda-calculus, which has a well-defined and wellunderstood meaning. To illustrate the Continuation-passing style, consider the ML program below: fun f x = x + 1 In CPS, all the intermediate results need to be named. Also, it would be helpful to name the return address let s call it k. Then we can express the returning of a function using continuations. A continuation is a function that expresses what to do next. We can give a function a continuation as one of its arguments, and apply the result to it when the function returns. So the CPS version of the above program might look like this: fun f (k, x) = let val x 1 = 1 in let val x 2 = x + x 1 in k x 2 end end Aside from that, the CPS-based language, i.e. our target language in lab1 has a similar syntax to that of the ML language. Figure 2 illustrates the syntax of the CPS language corresponding to the ML syntax in Figure 1. In the CPS syntax, we introduce the metavariable k to represent a continuation. Thus there are two kinds of application: the function application: f k x, in which function f takes two arguments: k and x. the continuation application: k x, corresponding to a jump or a return, to pass the partial result x via continuation k. Besides, you may have noticed that in pair value (x, y), tagged value in i x, case term case x of k 1 [] k 2, and the application terms, only variables rather than expressions (containing substructures) are allowed to exist. Also, in term 3

(terms) K letval x = V in K let x = π i y in K letcont k x = K in K k x f k x case x of k 1 [] k 2 letprim x = P rimop y in K if0 x then k 1 else k 2 letfix f k x = K in K (values) V () i s (x 1, x 2,..., x n ) in i x λk x.k (primitives) P rimop + print int2string Figure 2: CPS syntax let x = π i y in K (corresponding to project operation in the ML syntax), y (the subject to perform projection) is a variable. These alterations enforces that all intermediate results are named. The term Exit of string defined in file cps.sml and file cps.sig is considered to be a special kind of continuation application. It is for the purpose that initially, to translate an ML expression, a translate function κ which takes a variable and return a CPS expression need to be given as an arguments. A reasonable choice for the initial κ could be fn x => Exit(x). (See the Section 3 below to understand this.) Exercise 2. Finish the code in file cps.sml for the function dump2file that print the CPS expression to a text file. Before you start, make sure that you understand the datatype definition in file cps.sml and file cps.sig. Once again, the text you printed should be a legal function that can be executed in SML/NJ. You can test your implementation on the give example, or write some of your own examples. The CPS representation is easy for optimizing compilers to manipulate and transform. For example, we would like to perform tail-recursion elimination: If a function f calls a function g as the very last thing it does, then instead of passing g a return address within f, it could pass to g the return address that f was given by f s caller. Then, when g returned, it would return directly to the 4

caller of f. For more details, you may refer to Compiling with Continuations, Continued. 3 CPS Conversion In this section we will discuss how to perform CPS conversion. Expressions in ML can be translated into untyped CPS terms using the function shown in Figure 3. This is an adaptation of the standard higher-order one-pass call-byvalue transformation (Danvy and Filinski 1992). [ ] : ML (Var CTm) CTm [x]κ = κ(x) [()]κ = letval x = () in κ(x) [i]κ = letval x = i in κ(x) [ s ]κ = letval x = s in κ(x) [e 1 e 2 ]κ = [e 1 ](Λz 1.[e 2 ](Λz 2.letcont k x = κ(x) in z 1 k z 2 )) [(e 1,..., e n )]κ = ( [e 1,..., e n ], nil )(Λ l. letval x = tuple( l) in κ(x)) [ini e]κ = [e](λz.letval x = in i z in κ(x)) [#i e]κ = [e](λz.let x = π i z in κ(x)) [fn x => e]κ = letval f = λk x.[e](λz.k z) in κ(f) [let val x = e 1 in e 2 end]κ = letcont j x = [e 2 ] κ in [e 1 ](Λz.j z) [case e of in1 x 1 => e 1 in2 x 2 => e 2 ]κ = [e](λz.letcont k 0 x 0 = κ(x 0 ) in letcont k 1 x 1 = [e 1 ](Λz.k 0 z) in letcont k 2 x 2 = [e 2 ](Λz.k 0 z) in case z of k 1 [] k 2 ) [P rimop e ]κ = ( e, nil )(Λ l.letprim x = P rimop l in κ(x))) [let fix f x = e 1 in e 2 ]κ = letfix f k x = [e 1 ](Λz.k z) in [e 2 ]κ [if0 e 1 then e 2 else e 3 ]κ = [e 1 ](Λz.letcont k 0 x 0 = κ(x 0 ) in letcont k 1 x 1 = [e 2 ](Λz.k 0 z) in letcont k 2 x 2 = [e 3 ](Λz.k 0 z) in if0 z then k 1 else k 2 ) Figure 3: CPS Conversion The transformation works by taking a translation-time function κ as argument, representing the context into which the translation of the source term is 5

( ) : ML list * string list (string list CTm) CTm ( [], ω )η = η(rev(ω)) ( e :: es, ω )η = [e](λx.( es, x :: ω )η) Figure 4: CPS Conversion for tuples embedded. For our language, the context s argument is a variable, as all intermediate results are named. Note some conventions used in Figure 3: translationtime lambda abstraction is written using Λ and translation-time application is written κ(...), to distinguish from λ and juxtaposition used to denote lambda abstraction and application in the target language. Also note that any object variables present in the target terms but not in the source are assumed fresh with respect to all other bound variables. The translate procedure [ ] takes two arguments: 1. an ML term; 2. a translation-time function that convert a variable into a CPS term. The translation-time functions could be generated during the translate procedure, and will be used to generate CPS terms. As an example, consider the conversion [(fn x => 1) 2]]κ, where κ is assumed to be fn x => exit x: Firstly, we have rule [e 1 e 2 ]κ = [e 1 ](Λz 1.[e 2 ](Λz 2.letcont k x = κ(x) in z 1 k z 2 )) so the original expression is converted to: [fn x => 1](Λz 1.[2]](Λz 2.letcont k1 x = exit x in z 1 k1 z 2 )). k1 is a fresh continuation. As the rule to convert an integer goes to: we have [i]κ = letval x = i in κ(x), [fn x => 1](Λz 1.letval x1 = 2 Notice that the variable x1 is a fresh one. in letcont k1 x = exit x in z 1 k1 x1). Then, as the rule to convert an abstraction is: 6

[fn x => e]κ = letval f = λk x.[e](λz.k z) in κ(f), the original expression is converted to: letval f = λk x.[1]](λz.k z) in letval x1 = 2 in letcont k1 x = exit x in f k1 x1. Finally, apply the rule to convert a integer again, we have the result: letval f = λk x.letval x2 = 1 in k x2 in letval x1 = 2 in letcont k1 x = exit x in f k1 x1. As the CPS convert for an ML tuple need to generate a CPS tuple with indefinite length, we need a different function. Here we have an additional function, denoted as ( ) to help to translate an tuple expression (as shown in Figure 4). Note that ( ) and [[ ]. are mutually recursive. ( ) takes a pair of an ML tuple and a string list (representing the variables that already generated) and a function η that takes a string list and returns a CPS term. The rule for a tuple that is not empty: ( e :: es, ω )η = [[e](λx.( es, x :: ω )η), uses [e] to transfer the first expression, and then add the corresponding variable (will be the x when (Λx.( es, x :: ω )η) is applied) to the list ω. When all the expressions are converted, rule ( [], ω )η = η(rev(ω)) applies the function η on the reversion of list ω to generate the CPS as the result. (Function tuple convert a string list to a CPS tuple, function rev returns the reversion of a string list.) Think carefully about the rules above. e.g. Why in ( [], ω )η = η(rev(ω)), the list ω is converted? It will be helpful for you to write some examples and do the translation by hand to understand the procedure. Exercise 3. Finish the code in file cps-convert.sml for the function trans that convert the ML expressions into CPS expressions. Before you start, make sure that you understand the rules in Figure 3 and the example we discussed above. The utility function freshcont and freshval are provided to generate new variable and continuation names. You can test your implementation on the give example, or write some of your own examples. 7