Space-Efficient Blame Tracking for Gradual Types

Size: px
Start display at page:

Download "Space-Efficient Blame Tracking for Gradual Types"

Transcription

1 Space-Efficient Blame Tracking for Gradual Types Jeremy G. Siek University of Colorado at Boulder Abstract Static and dynamic type systems have well-known strengths and weaknesses. Gradual typing provides the benefits of both in a single language by giving the programmer control over which portions of the program are statically typed and which portions are dynamically checked based on the presence or absence of type annotations. A compiler for a gradually typed language infers where the dynamic checks are needed and inserts casts into the intermediate language to perform these checks. Herman, Tomb, and Flanagan noticed that casts in higher-order languages can cause space leaks proportional to the execution time of the program. They developed a solution that merges sequences of casts. On a separate front, Findler and Wadler developed blame tracking for a language similar to the intermediate language of gradual typing. Blame tracking solves the problem of tracing a run-time cast failure back to the source of the error. Findler and Wadler proved that well-typed portions of a program can t be blamed. Blame tracking requires extra information to be stored in casts and whether this information can be merged to obtain space efficiency is an open question. This paper answers the question in the affirmative by developing a dynamic semantics for gradual types that is both space efficient and tracks blame. This paper also improves the precision of blame tracking by reporting what part of the cast caused the error. Categories and Subject Descriptors D.3.3 [Programming Languages]: Language Constructs and Features; F.3.3 [Logics and Program Constructs]: Studies of Program Constructs Type structure General Terms Languages, Algorithms Keywords dynamic typing, static typing, gradual typing, contracts, blame tracking, space efficiency 1. Introduction Static and dynamic typing have complementary strengths, making them better for different tasks and stages of development. Static typing, used in languages such as Standard ML (Milner et al. 1990) and Haskell (Peyton Jones 2002), provides full-coverage type error detection, facilitates efficient execution, and provides machinechecked documentation that is particularly helpful for maintaining consistency when programming in the large. The main drawback of static typing is that the whole program must be well-typed before [Copyright notice will appear here once preprint option is removed.] the program can be run. Typing decisions must be made for all elements of the program, even for ones that have yet to stabilize, and changes in these elements can ripple throughout the program. In a dynamically typed language, no compile-time checking is performed. Programmers need not worry about types while the overall structure of the program is still in flux, making dynamic languages suitable for rapid prototyping. Dynamic languages such as Perl, Ruby, Python, and JavaScript are popular for scripting and web applications where rapid prototyping is needed. The problem with dynamic languages is that they forgo the benefits of static typing: there is no machine checked documentation, execution is less efficient, and errors are caught only at runtime, often after deployment. Gradual typing, recently introduced by Siek and Taha (2006), enables programmers to mix static and dynamic type checking in a program by providing a convenient way to control which parts of a program are statically checked. The defining properties of a gradual type system are: 1. Programmers may omit type annotations and immediately run the program; run-time type checks are performed to preserve type safety. 2. Programmers may add type annotations to increase static checking. When all variables are annotated, all type errors are caught at compile-time. The compiler for a gradually typed language inserts casts in the intermediate language at the boundaries between typed and untyped portions of code. The semantics of these casts is based on the more general notion of contracts developed by Findler and Felleisen (2002). However, Herman et al. (2007) noticed that in higher-order languages (e.g., languages with first class functions or objects), casts can cause space leaks that grow in size proportional to the execution time of the program. They solve this problem by applying casts to higher-order values in a lazy fashion and by developing a technique for merging casts based on the coercion calculus of Henglein (1994). A second problem with casts in higher-order languages is that it can be difficult for the programmer to trace a run-time cast failure back to the source of the problem. In the context of contracts, Findler and Felleisen (2002) show how to provide run-time support for this, called blame tracking, by maintaining extra information within casts. Tobin-Hochstadt and Felleisen (2006) study a language in which modules can be either statically or dynamically typed and casts perform run-time type checking at the boundaries. They prove that when a cast error occurs, the blame never traces back to a statically-typed module. Wadler and Findler (2007) adapt these techniques to an intermediate language similar to the one used for gradual typing and prove that well-typed portions of a program can t be blamed. To make gradual typing practical for industrial strength languages, we need both space efficiency and blame tracking. However, because blame tracking requires extra information in casts, it /4/17

2 γ G {int, bool} ground types ::= γ? types x V variables n Z integers c K {n, true, false} constants e ::= x λx :. e (e e) expressions if e then e else e λx. e λx :?. e Figure 1. Syntax of the gradually typed lambda calculus (λ? ). is not straightforward to perform blame tracking while at the same time merging casts to achieve space efficiency. In fact, for contracts it is not possible to obtain space efficiency because general predicates cannot always be merged in a way that saves space. Nevertheless, in this paper we show that space efficient blame tracking is possible for the gradually typed lambda calculus (Siek and Taha 2006). Going further, we improve blame tracking by identifying which part of a cast caused the error. We call this variant highfidelity blame tracking. The technical contributions of this paper are: The definition of a space-efficient dynamic semantics for the gradually typed lambda calculus that performs high-fidelity blame tracking (Section 4). We show that for a given program, the extra space needed during program execution for casts and blame tracking information is a constant factor (Section 5.1). We show that the space-efficient semantics is observationally equivalent to the straightforward semantics (Section 5.2). We prove that the space-efficient semantics is type safe and that well-typed regions of a program can t be blamed (Section 5.3 and 5.4). We have implemented the semantics in Isabelle (Nipkow et al. 2007) and automatically generated an OCaml implementation. The type safety proof is formalized in Isabelle and the formalization of the other properties is ongoing work. The Isabelle theory and OCaml implementation is available on the author s web page. The paper proceeds as follows. We review gradual typing (Section 2) then review blame tracking and present high-fidelity blame tracking (Section 3). We then turn to the space efficiency problem, reviewing the solution of Herman et al. (2007) and deliver the main contribution of the paper: a space efficient dynamic semantics that performs blame tracking (Section 4). We prove several properties of this semantics: that it is indeed space efficient, that it is equivalent to the straightforward semantics, and that it is type safe and blame safe (Section 5). The paper ends with a survey of related work (Section 6) and the conclusion (Section 7). 2. Review of Gradual Typing The gradual type system provides dynamic checking in regions of a program that do not have type annotations, and provides static typing in regions of a program that do have annotations. Furthermore, gradual typing enables the migration from dynamic to static by allowing mixed regions where some variables are annotated and some are not. The syntax of the gradually typed lambda calculus (Siek and Taha 2006), written λ?, is shown in Figure 1. The syntax is similar to that of the simply typed lambda calculus but with the addition of the dynamic type?. A function with an un-annotated parameter is syntactic sugar for a function whose parameter is annotated with?. The gradual type system classifies dynamically typed expressions as having type Dynamic, which we abbreviate to?, and allows implicit coercions from any type to? and from? to any other type. Consider the following program written in the gradually typed lambda calculus. let a = 1 in let add1 = λx. x + 1 in (add1 a) We take the liberty of using let expressions in examples and assign the type of the right-hand side to be the type of the let-bound variable. So a has type int and add1 has type? int. In the function application (add1 a) there is an implicit coercion from int to?. This kind of coercion is safe and, in general, allows statically typed code to seamlessly pass values into dynamically typed code. Inside function add1, the variable x of type? is passed to the addition operator. To simplify the present discussion, suppose + has the type int int int. The gradual type system also allows this implicit coercion from? to int, even though these coercions may not always succeed. To preserve type safety, the compiler inserts an explicit cast in the intermediate representation and the cast performs a run-time check, just as in a dynamically typed language. In general, this kind of coercion allows dynamically typed code to seamlessly pass values into statically typed code. Motivation for implicit casts The goal of gradual typing is to enable a smooth migration between dynamic and statically typed code. In the gradual type system, a programmer adds type annotations to function parameters to migrate from dynamic to static, and the compiler inserts or removes casts as needed. If instead the casts were explicit, then every change to a parameter s type annotation would require the programmer to manually insert or remove casts everywhere the parameter is used. This extra work creates an unnecessary barrier to migrating code between dynamic and static typing. Why not use subtyping? Gradual typing allows an implicit upcast from any type to?, similar to object-oriented type systems where Object is the top of the subtype lattice. However, gradual typing differs in that it also allows implicit down casts. This is the distinguishing feature of gradual typing and is what gives it the flavor of dynamic typing. Previous attempts at mixing static and dynamic typing, such as the Quasi-static Typing of Thatte (1990), tried to use subtyping but had to deal with the following problem. If the dynamic type is treated as both the top and the bottom of the subtype lattice (allowing both implicit up-casts and downcasts), then the lattice collapses to one point because subtyping is transitive. In other words, every type is a subtype of every other type and the type system no longer rejects any programs, even ones with obvious type errors. Consider the following program. let add1 = λx : int. x + 1 in (add1 true) Using true as an argument to the function add1 is an obvious type error but we have bool <:? and? <: int, so bool <: int. Thus the subtype-based type system would accept this program. Thatte partially addressed this problem by adding a post-pass after the type checker but this still did not result in a system that catches all type errors within fully annotated code (Oliart 1994). The consistency relation Instead of using subtyping, the gradual type system uses a relation called consistency (Siek and Taha 2006), written. The intuition behind consistency is to check whether two types are equal in the parts where both types are de /4/17

3 fined (i.e. not?). Here are a few examples: int int bool int? int int? int?? int int? bool? int? int bool int int int bool The following is the inductive definition of the consistency relation. Here we limit the definition to function types but it can be extended to other type constructors such as object types (Siek and Taha 2007). We use the metavariable to range over arbitrary types and γ to range over ground types such as int and bool. Type Consistency γ γ?? The consistency relation is reflexive and symmetric but not transitive. The consistency relation is symmetric because we want to allow implicit coercions both to and from? as explained above. The lack of transitivity is necessary for the gradual type system to still have a static flavor and reject some programs. For example, because bool int, the gradual type system properly rejects the function call (add1 true) in the previous example. At first glance, the consistency rule for function types may seem strange because it is not covariant and contravariant in the same way as a subtype relation. Because consistency is symmetric, it does not make sense to talk of covariance and contravariance: flipping 1 3 to 3 1 does not make a difference. The gradual type system uses consistency where a simple type system uses type equality. For example, at a function application, the argument type is allowed to differ from the function s parameter type so long as the two types are consistent. Well-typed regions In Section 5.4 we show that well-typed regions of a gradually typed program can not cause cast errors. We define a well-typed region to be an expression that only contains safe implicit coercions. Safe coercions are characterized by the following subtyping relation in which the dynamic type? plays the role of top. Subtyping <:? γ <: γ 3 <: 1 2 <: <: 3 4 When migrating code from dynamic to static, a programmer may want to assert that the migration is complete for a particular region of code and ask the compiler to give an error if there are any remaining unsafe casts in the region. This is straightforward to accommodate by adding an expression of the form (static e) where the type system signals an error if e can not be type checked using the type rules of the simply typed lambda calculus with subtyping. This feature is implemented in our prototype but we do not discuss it further in this paper. 2.1 The semantics of casts Broadly speaking, there are two ways to implement the run-time behavior of a gradually typed language after the gradual type checking phase is complete. One option is to erase the type annotations and execute the program with normal dynamic checking. This is an easy way to extend a dynamically checked language with gradual typing. The disadvantages of this approach is that unnecessary run-time type checks are performed and some errors become manifest later in the execution of the program or not at all, as we show in an example below. The second approach only performs run-time type checks at the boundaries of dynamically and statically typed code. The advantage is that statically typed code performs no run-time type checks. But there is an extra cost in that run-time tags contain complete types so that values may be completely checked. There are observable differences between the two approaches. The following example runs to completion with the first approach but produces an error with the second approach. let id = λx : int. x in let y :? = false in (id y) In the next example, both approaches produce run-time cast errors. The second approach signals an error when false is passed to add1 whereas the first approach signals an error later on, when false is passed to the addition operator. let add1 = λx : int. x + 1 in let y :? = false in (add1 y) The gradually typed lambda calculus takes the second approach. The locations of the run-time type checks are specified by a castinserting translation to an intermediate language with explicit casts named λ?. Casts take the form 2 1 pn e, where 1 is the type of the expression e and 2 is the target type. The p and n are blame labels which we discuss in Section 3 but ignore in this section. Only the target type is really necessary but including both simplifies the specification of the static and dynamic semantics of the intermediate language. As an example of cast-insertion, consider the translation of the above example. let add1 = λx : int. x + 1 in let y :? =? bool false in (add1 int? y) A cast is inserted around the constant false so that its type matches the type of y. A cast is also inserted around the occurrence of y in (add1 y) because the add1 function expects an integer. The cast-insertion translation is defined in Figure 2. This translation is type-directed and is nearly identical to the type system of the gradually typed lambda calculus; it just adds an output expression. To save space we do not separately present the type system for the gradually typed lambda calculus but give its definition in terms of the cast-inserting translation by ignoring the output expression. The cast-inserting translation relies on several auxiliary functions. The notation 2 1 e stands for 2 1 e if 1 2 and otherwise stands for just e thereby avoiding trivial casts. The lookup function finds the value associated with a key in an association list. The typeof function assigns types to constants. Its definition depends on the choice of the set of constants K. The gradual typing rule for if expressions requires that the types of the then and else branches be consistent with one another, or equivalently, that there exists a least upper bound (lub) with respect to the less informative relation. The type of the if expression is the lub which is computed by the join operator defined below. Less informative relation and its join operator? γ γ γ γ = γ? =? = ( 1 2) ( 3 4) = ( 1 3) ( 2 4) /4/17

4 Γ ::= [] (x, ) Γ type environments Γ g e : Γ e e : Γ g e : e. Γ e e : lookup(γ, x) = Γ x x : typeof(c) = γ Γ c c : γ (x, 1) Γ e e : 2 Γ (λx : 1.e) (λx : 1 : e ) : 1 2 Γ e 1 e 1 : 1 1 bool Γ e 2 e 2 : 2 Γ e 3 e 3 : 3 4 = 2 3 Γ (if e 1 then e 2 else e 3) (if bool 1 e 1 then 4 2 e 2 else 4 3 e 3) : 4 Γ e 1 e 1 : 1 3 Γ e 2 e 2 : Γ (e 1 e 2) (e e 2) : 3 Γ e 1 e 1 :? Γ e 2 e 2 : Γ (e 1 e 2) (?? e 1 e 2) :? Figure 2. The type system for λ? and the cast-inserting translation from λ? to λ?. 2.2 The intermediate language with explicit casts Figure 3 gives a definition of the intermediate language, including the syntax, type system, and dynamic semantics. The type system is that of the simply typed lambda calculus extended with a cast expression. The type rule for casts requires that the target type of the cast be consistent with the source type. We express the dynamic semantics in a style inspired by Gurevich s Abstract State Machines (ASMs) (Gurevich 1995; Cater and Huggins 1999). The semantics is small-step, uses environment passing instead of substitution, and explicitly represents the procedure call stack. The semantics is similar to the SECD machine but does not use an operand stack S, so perhaps ECD would be a good name for this machine. ASMs typically use a pointer to keep track of what needs to be executed next but we use evaluation contexts. 1 The choice of ASM-style semantics is motivated by the need in the space-efficient semantics to focus on function call boundaries. A machine state is a triple consisting of an expression (the body of the active function), an environment (binding variables to values), and a function call stack. Each frame on the stack contains an evaluation context and an environment. Most of the state transition rules in Figure 3 are straightforward but the dynamic semantics of casts deserves some explanation. We follow the treatment of casts in Siek and Taha (2006), adapting the approach to a small-step semantics. When a cast is applied to a value, the course of action depends on the form of the value and the target type of the cast. Note that a value is either a constant or closure (which we call simple values) or a simple value enclosed in a cast whose target type is?. If a cast with target type? is applied to a simple value, we leave the cast as-is to note that the value has been injected into the dynamic type. The source type of the cast gives the run-time type of the value. If a cast is applied to a value that is already cast to?, then the CSTOK rule performs a check to make sure that the cast s target type is consistent with the run-time type of the value and removes the cast if the two types are the same. If the target type of the cast is a function type, then rule CSTFUN applies, and the cast is replaced by a wrapper function that casts the parameter and result appropriately. An alternative to generating wrappers is to leave a cast to a function type in place and provide an extra rule for function application that deals with casts around the function (Wadler and Findler 2007). In our setting the extra rule would look like: (CSTAPP) E[( v 1 v 2)], ρ, κ E[ 4 2 (v v 2)], ρ, κ 1 The author learned of using evaluation contexts with ASMs in a course taught by Amr Sabry. This alternative does not, by itself, resolve the space efficiency problem because sequences of function casts can build up. However, Herman et al. (2007) combine this alternative with rules for merging casts to solve the space efficiency problem. We build on their solution by adding blame tracking in Section Type safety of gradual typing Siek and Taha (2006) proved two kinds of type safety for a bigstep semantics of gradual types. Here we adapt those results to the small-step semantics. Recall that the cast-inserting translation produces a well-typed expression in the intermediate language. Lemma 1 (Cast insertion is sound). If Γ e e : then Γ e :. If a program does not contain type annotations with?, then the cast-inserting translation does not insert any casts. Lemma 2 (No casts in fully annotated code). If the type? does not appear in a type annotation in e, and if Γ e e :, then there are no casts in e. We define a run-time cast error as follows Definition 1 (Cast Error). A cast error is an expression of the form 2?? 1 s where 1 2. and single out three kinds of machine states. Definition 2 (Terminal, Final, and Stuck States). A state σ is terminal if σ. σ σ. A state σ is final if σ is of the form v, ρ, []. A state is stuck if it is terminal but not final. The occurrence of a run-time type error is modeled by a sequence of state transitions that end in a stuck state. The intermediate language enjoys both progress and preservation. Lemma 3 (Progress and Preservation). If σ then either 1. there is a σ such that σ σ and σ, or 2. σ is a final state, or 3. σ contains a cast error. Proof. The proof is a simplified version of the proof in Section 5.3 for the space-efficient semantics. Theorem 1 (Type Safety). If e e :, e, [], [] σ, and σ is a terminal state, then either 1) σ is a final state v, ρ, [] and v :, or 2) σ contains a cast error /4/17

5 Syntax: ::= γ? e ::= x λx :. e (e e) if e then e else e pn e s ::= c λx :. e, ρ v ::= s? s Type system: lookup(γ, x) = Γ x : Run-time structures: E ::= (E e) (v E) E if E then e else e evaluation contexts ρ ::= [] (x, v) ρ environments κ ::= [] (E, ρ) κ procedure call stacks σ ::= e, ρ, κ state typeof(c) = γ Γ c : γ Γ e 1 : bool Γ e 2 : Γ e 3 : Γ if e 1 then e 2 else e 3 : Well-typed run-time structures: Γ : Dynamic semantics: Γ, x : 1 e : 2 Γ e 1 : 1 2 Γ e 2 : 1 Γ e : Γ λx : 1.e : 1 2 Γ (e 1 e 2 ) : 2 Γ 2 1 pn e : 2 Γ E 1 : Γ e 2 : 1 Γ (E 1 e 2 ) : 2 Γ e 1 : 1 2 Γ E 2 : 3 1 Γ (e 1 E 2 ) : 2 Γ E : Γ 2 1 E : 3 2 [] : Γ E 1 : 1 bool Γ e 2 : 2 Γ e 3 : 2 Γ if E 1 then e 2 else e 3 : 2 [] [] v : Γ ρ (x, ) Γ (x, v) ρ Γ ρ Γ E : 1 2 κ : 2 3 Γ e : 1 Γ ρ κ : 1 2 (E, ρ) κ : 1 3 e, ρ, κ (VAR) E[x], ρ, κ E[v], ρ, κ where v = lookup(ρ, x) (LAM) E[λx :. e], ρ, κ E[ λx :. e, ρ ], ρ, κ (CALL) E[( λx :. e, ρ v)], ρ, κ e, (x, v) ρ, (E, ρ) κ where E (TAILCALL) ( λx :. e, ρ v), ρ, κ e, (x, v) ρ, κ (RET) v, ρ, (E, ρ ) κ E[v], ρ, κ (DELTA) E[(c v)], ρ, κ E[v ], ρ, κ where v = δ(c, v) (IFT) E[if true then e 2 else e 3 ], ρ, κ E[e 2 ], ρ, κ (IFF) E[if false then e 2 else e 3 ], ρ, κ E[e 3 ], ρ, κ (CSTOK) E[ 2? p n? 1 pn s], ρ, κ E[ 2 1 p n s], ρ, κ where 1 2 (CSTFUN) E[ pn s], ρ, κ E[λx : pn (s 1 3 np x)], ρ, κ [e] = e (E 1 e 2 )[e] = (E 1 [e] e 2 ) (v 1 E 2 )[e] = (v 1 E 2 [e]) (if E 1 then e 2 else e 3 )[e] = if E 1 [e] then e 2 else e 3 Figure 3. Static and dynamic semantics for the intermediate language λ?. Proof. The proof applies Lemma 1 then proceeds by induction on the sequence of state transitions, using Lemma 3. Theorem 2 (Static Type Safety). If e contains no type annotations with?, e e :, e, [], [] σ, and σ is a terminal state, then σ is a final state v, ρ, [] and v :. Proof. This is a consequence of Lemma 2 and Theorem Blame tracking In languages with first-class functions, determining the cause of a cast error is non-trivial. The casts used in gradual typing are a special case of the contracts of Findler and Felleisen (2002), and they show how to provide run-time support for tracing a contract violation back to the cause. The term blame tracking is used to refer to this run-time support. Consider the following gradually typed program that results in a cast error. let g = λh :? int. (h true) in let add1 = λx : int. x + 1 in (g add1 ) The run-time cast error occurs at (h true), where the Boolean true is passed to the add1 function, which expects an integer. The origin of the problem, however, is the application (g add1 ), where the add1 function is implicitly coerced from int int to? int. A blame tracking system traces the error back to where the cast originated. To understand a cast error it is also important to determine which side of the cast is to blame, the producer (the expression within the cast) or the consumer (the user of the cast value). In this example, the consumer is to blame: the use of the add1 function in the application (h true) violates the parameter type of add Findler and Felleisen blame tracking Findler and Felleisen (2002) keep track of who is to blame by associating two blame labels with each cast, one positive label (to blame the producer) and one negative label (to blame the consumer). Carrying this idea over to casts results in casts of the form pn e (Wadler and Findler 2007). The dynamic semantics defined in Figure 3 uses the Findler and Felleisen approach to blame tracking. For example, the CSTFUN rule reverses the blame labels inside the wrapper function, where the cast applied to param /4/17

6 eter x: E[ pn s], ρ, κ E[λx : pn (s 1 3 np x)], ρ, κ The blame labels reverse because the producer-consumer relation flips; the consumer of the function is the producer of the argument bound to x. Going back to our example with the function g and add1, the call (g add1 ) appears in the intermediate representation as which evaluates to (g? int int int p 1n 1 add1 ) (g (λx :?. (add1 int? n 1p 1 x))). Skipping ahead a few evaluation steps, to the function application (h true), we have ((λx :?. (add1 int? n 1p 1 x))? string p 2n 2 true) (add1 int? n 1p 1? string p 2n 2 true) which is a cast error because string int. The first blame label in the failed cast is the negative label n 1, so the consumer of the cast (? int int int p 1n 1 add1 ) is to blame. The Findler and Felleisen approach to blame tracking reports which cast was to blame and whether the producer or the consumer was at fault. However, this approach does not tell the programmer precisely what part of the target type caused the error. Consider a slightly more complicated example: 1 let h = λk : (int int) int. (k add1 ) in 2 let g = λf :??. (f true) in 3 (h g) The cast error occurs at (f true) and can be traced back to the implicit coercion of g in (h g) from (? int)? to (int int) int. The blame is positive, so the producer g is at fault. However, there s a couple ways that g could have violated the cast: it could be using parameter f incorrectly or it could be returning a value of the wrong type. For someone familiar with higher-order casts, it may be straightforward to see that g is misusing f by passing in a Boolean value where an integer is expected. However, for those less familiar with higher-order casts, this can be difficult to discern. 3.2 High-fidelity blame tracking To improve the precision of cast error diagnostics, we propose an alternative approach to blame tracking, which we name highfidelity blame tracking. Our goal is to tell the programmer which part of the target type in a cast was to blame for the cast error. For example, given the above program with functions h and g, we would like to produce an error message like the following. line 3: cast error! expected value of type: ( int int) int but, for the indicated location, got a value of type: bool the producer is to blame: g location that triggered the error: line 2 The box indicates the precise location of the cast error, in this example the parameter type of the parameter f of function g. Whether the blame is positive or negative can be easily computed given the location of the box: if the box is in a positive location in the type, the blame is positive, and similarly for a negative location. In this example the box is in a positive location, so the blame goes to the producer g. Implementing high-fidelity blame tracking is not straightforward because, at the point where the cast error is triggered, we no longer have the entire target type from the original cast: the type has been broken down into pieces. Recall that when a cast is applied to a function, a wrapper function is generated and the cast is split into two casts: one on the parameter and one on the return value. In the above example, the cast error is triggered on line 2 where we have a failed cast from bool to int. So the question is: how can we keep track of where this int came from? We solve this problem by enriching the information in a cast to include the context of the source and target type. Given a type with a sub-type distinguished by a box, such as ( int int) int, the context is everything outside the box. We define a grammar for type contexts as follows. The represents the hole in the context. T ::= T T Casts now take the form T [] T [] e. Next we address how to maintain contexts within casts during evaluation. The following is the rule for casting to a function type, but we need to determine the contexts on the right-hand. (The indicate where contexts need to be placed.) T 1[ 3 4] T 2[ 1 2] s (λx : 3. [ 4] [ 2] (s [ 1] [ 3] x)) The contexts on the right-hand side need to be the contexts T 1 and T 2 but with their holes partially filled-in. This is expensive to do with normal (outside-in) contexts. However, if we express the contexts in a inside-out manner, then partially filling the hole becomes a constant time operation. Here is the definition of insideout type contexts X ::= context items T ::= [] X T type contexts The following plug function takes a inside-out context and a type and returns the result of filling the hole within the context with the given type. plug : T plug([], ) = plug(( 2) T, 1) = plug(t, 1 2) plug(( 1 ) T, 2) = plug(t, 1 2) The reduction rule for casting to a function type then becomes: T 1[ 3 4] T 2[ 1 2] s (λx : 3. ( 3 ) T 2[ 4] ( 1 ) T 1[ 2] R) where R = (s ( 2) T 1[ 1] ( 4) T 2[ 3] x) 4. Space efficiency There are two ways that casts can cause unbounded space leaks. The first is that a program may apply many casts to the same function, resulting in a build-up of wrapper functions. Herman et al. (2007) give the following example: let rec even = λn : int. λk :??. if n = 0 then (k true) else (odd (n 1) k) and odd = λn : int. λk : bool bool. if n = 0 then(k false) else (even (n 1) k) Each time the function bound to k is passed between even and odd it is wrapped within another function causing a space leak proportional to n. The second kind of space leak affects tail-recursive functions such as in the following variant of the above example (Herman et al /4/17

7 2007). let rec even : int? = λn : int. if n = 0 then true else (odd (n 1)) and odd = λn : int. if n = 0 then false else (even (n 1)) The application (even (n 1)) appears to be a tail call, but because the return type of even is? it is not a tail call. Upon returning, the result of even must be cast from? to bool. Ideally, the even and odd functions would require only a constant amount of space, but because the call to even is no longer a tail call, the run-time stack must grow with each call and the extra space consumption is proportional to n. The solution given by Herman et al. (2007) to these problems requires three changes to the semantics: 1. apply casts to functions in a lazy manner, i.e., only at function application, 2. merge sequences of casts into a single cast, and 3. check for sequences of casts in tail-position and merge them before making function calls. Lazy function type casts To allow the lazy application of casts whose target is a function type, we change the definition of values to allow casts with arbitrary target types (instead of restricting them to?). v ::= s s values We then remove the CSTFUN rule and add the CSTAPP rule that was discussed in Section 2.2. The CSTAPP rule handles a function application where the function is surrounded by a cast. It breaks the cast up into a cast on the argument and a cast on the result of the application. Merging casts To accomplish the merging of casts, Herman et al. (2007) use the coercion calculus of Henglein (1994) to express casts. The coercion calculus represents a cast as a sequence of primitive coercion instructions. Two casts can be merged by appending the two sequences of coercions and then normalizing. The normalization process ensures that the space is bounded by the size of the source and target types. In this paper we take an equivalent but more declarative approach. Our intuition is that a sequence of casts can be summarized by a single type that represents the high-water mark of the types in the intermediate casts. More formally, the sequence of types is summarized by their least upper bound with respect to the less informative relation. To keep track of the least upper bound, we enrich casts to include three types instead of just two: we add a middle type. We typeset the middle type above the symbol, so the new casts have the form e. A sequence of old-style casts n n e can then be summarized by the new cast n 1 e where = { n 1,..., 2}. The following is the typing rule for the new casts. Γ e : Γ e : 3 The middle type is required to be greater or equal to the source and target type. The middle type can therefore be seen as a witness that 1 3. We also require that 1 be different from either 2 or 3 to prevent trivial casts. Recall that to perform high-fidelity blame tracking we need to keep track of the type context. Furthermore, we need a way to somehow merge type contexts in parallel with the merging of the middle type. This can be accomplished with a rather simple idea. An inside-out context can be seen as a way of traversing from a sub-type to its parent and on to its ancestors. So instead of using a separate data structure for inside-out contexts, we include parent pointers in the types. Given a pointer to a type, we access its context by walking up the parent pointers. The abstract syntax for types is enriched as follows to include the parent pointers p P parent pointers ::= γ p? p p types and we use a parent function that maps a type to its parent type (or expression, as the parent pointer of the top-most type within a cast points to the cast). The blame function, defined below, follows the parent pointers and returns the enclosing cast, type context, and polarity of the blame (+ or ). We use the notation o to flip the polarity. blame() = let rec loop(, T, o) = case parent() of 1 2 if = 1 then loop(parent(), ( 2) T, o) else loop(parent(), ( 1 ) T, o) e ( e, T, o) in loop(, [], +) We update the join operator to handle parent pointers as shown below. The join operator for types with parent pointers γ p1 γ p2 = γ p2? p1 p2 = p2 p1? p2 = p1 ( 1 p1 2) ( 3 p2 4) = ( 1 3) p2 ( 2 4) The choice of which parent pointer to use in the result type is motivated by the desire to have the parent pointer always be associated with the first type that would have caused a cast error. 2 When merging two casts: , we apply the join operator 7 = 5 2 to obtain the middle type for the merged cast: We give precedence to the parent pointers in the type on the right, in this case to 2, because the inner cast would have been applied before the outer cast. The join operator is no longer symmetric because the ordering of arguments affects the choice of parent pointer. When a cast error occurs, that is, when we have an expression of the form s where 1 5, then we can recover the type context and the location of the original cast by applying the blame function to 5. The method of using parent pointers to accomplish blame tracking can be easily adapted to the coercion calculus. 2 Herman et al. (2007) allude to this in their future work section /4/17

8 Merging casts in tail position Herman et al. (2007) show how to merge tail-position casts in the CEKS machine (Felleisen and Flatt 2007) by reworking the definition of evaluation contexts. We adapt those ideas to the ASM-style semantics. Tail calls and casts are easy to identify in this semantics because the stack separates the evaluation contexts at function calls. In the straightforward semantics, casts in tail-position prevent the tail-call optimization rule TAILCALL. To make it easy to identify casts in tail position we use inside-out evaluation contexts. The following is the definition of inside-out evaluation contexts. C ::= ( e) (v ) if then e else e E ::= [] C E The following is the plug function for inside-out evaluation contexts. As usual, we write plug(e, e) as E[e]. [][e] = e (( e 2) E)[e 1] = E[(e 1 e 2)] (e 1 ) E)[e 2] = E[(e 1 e 2)] (if then e 2 else e 3 E[e 1] = E[if e 1 then e 2 else e 3] With inside-out contexts we can identify a cast in tail-position by checking whether the stack has the form ( E, ρ ) κ Now if the body of the current function call is a cast expression, we can merge that cast into the cast on the top of the stack. (TAILMERGE) e, ρ, ( E, ρ ) κ e, ρ, ( E, ρ ) κ where 7 = 5 2 As an aside, the merging of casts in tail position is analogous to the merging of update markers in the Lazy Krivine Machine (Friedman et al. 2007). Also, we note that continuation marks (Clements 2005) can be used to implement the TAILMERGE rule. Some care must be taken when the tail-position casts would produce a cast error (when 5 2). We can not immediately signal an error because that would amount to changing the evaluation order of the language. We instead introduce a new kind of cast that always fails k ::= fail : e ::=... k e C ::=... k and place it on the stack to signal an error if execution ever returns to this point. (TAILFAIL) e, ρ, ( E, ρ ) κ e, ρ, ( fail : E, ρ ) κ where 2 5 This is the last ingredient needed for space-efficient blame tracking. Figure 4 gives the complete definition of a space-efficient machine that performs high-fidelity blame tracking. 5. Properties of the space-efficient semantics There are several key properties that define what it means for the space-efficient semantics we define in Figure 4 to be correct. First we show that the semantics really is space efficient, that the casts only increase the amount of space needed by a constant factor for a given program. Second we show that the space-efficient semantics is equivalent to the straightforward semantics, including being equivalent with respect to the result of blame tracking. Lastly, we prove the standard type safety property and show that welltyped regions can t be blamed. 5.1 Space efficiency In this section we prove that the optimizations we applied to the dynamic semantics do indeed remove the space leaks. The proof is an adaptation of the proof of Herman et al. (2007). We establish several lemmas and then prove the main theorem, which states that the size of the machine states is bounded by the ideal size (in which casts take up no space) multiplied by 2 height(), where is the largest type in the program. The number 2 height() is constant for a given program, so this says the space consumption of the casts is a constant factor. Lemma 4 (Size bounded by height). size() 2 height() 1 Proof. By induction on. Lemma 5 (Height of join). height( 1 2) = max(height( 1), height( 2)) Proof. By induction on 1. Lemma 6 (Size of casts). If e e : and e, [], [] σ and σ contains e, then there is a e such that size( 2) 2 height( ) 1 and similarly for 1 and 3. Proof. The proof is by induction on the reduction sequence. The type 2 either comes from a preexisting type, or it is the result of a join. In either case (using Lemma 5 for the later) there is some pre-existing type such that height( 2) height( ). Then by Lemma 4 we have size( 2) 2 height( ) 1. The proof is simpler for 1 and 3. Definition 3 (Size and ideal size). The size function is defined in a straightforward manner for all the components of a machine state. The size ideal is defined similarly, except that it does not count the size of casts. Theorem 3 (Space efficiency). If e e : and e, [], [] σ then there is a e such that size(σ) O(2 height( ) size ideal (σ)). Proof. The reduction rules prevent the appearance of more than two consecutive casts, in particular the MERGE rule prevents them from appearing inside expressions and values, and the TAILMERGE rule prevents consecutive casts that span function call boundaries, that is, from the expression component into the stack component of the sate. Therefore the number of casts in the state is proportional to size ideal (σ). From Lemma 6 the size of each cast is in O(2 height( ) ) where is the largest type in e. Thus, there is a e such that size(σ) O(2 height( ) size ideal (σ)). 5.2 Equivalence to the straightforward semantics In this section we show that the space-efficient version of the semantics is observationally equivalent to the straightforward semantics. The straightforward semantics, denoted 1, is the semantics from Figure 3. As an intermediate step, we show that 1 is equivalent to a semantics that does not generate function wrappers, but instead uses rule CSTAPP, denoted 2. We then show that 2 is equivalent to the space-efficient semantics given in Figure 4, denoted 3. The equivalences are proven by establishing a bisimulation relation 1 between 1 and 2 and 2 between 2 and 3. Lemma 7 (Weak bisimulation between 1 and 2). If σ 1 1 σ 2 then /4/17

9 Syntax: ::= γ p? p p k ::= fail : e ::= x λx :. e (e e) if e then e else e k e s ::= c λx :. e, ρ v ::= s s Type system: Γ, x : 1 e : 2 Γ λx : 1.e : 1 2 Well-typed run-time structures: Γ [] : lookup(γ, x) = Γ x : typeof(c) = γ Γ c : γ Γ e 1 : 1 2 Γ e 2 : 1 Γ (e 1 e 2 ) : 2 Run-time structures: C ::= ( e) (v ) k if then e else e context items E ::= [] C E evaluation contexts ρ ::= [] (x, v) ρ environments κ ::= [] (E, ρ) κ procedure call stacks Γ e 1 : bool Γ e 2 : Γ e 3 : Γ if e 1 then e 2 else e 3 : Γ e : Γ e : 3 Γ e : 1 Γ fail : e : 3 Γ E : 2 4 Γ e 2 : 1 Γ ( e 2 ) E : ( 1 2 ) 4 Γ E : 2 4 Γ e 1 : 1 2 Γ (e 1 ) E : 1 4 Γ E : 3 4 Γ E : 1 2 Γ e 2 : 1 Γ e 3 : 1 Γ fail: E : 1 4 Γ (if then e 2 else e 3 ) E : bool 2 [] [] Dynamic semantics: [] : Γ E : Γ E : 1 4 v : Γ ρ (x, ) Γ (x, v) ρ Γ E : 1 2 Γ ρ κ : 2 3 Γ e : 1 Γ ρ κ : 1 2 (E, ρ) κ : 1 3 e, ρ, κ (VAR) E[x], ρ, κ E[ρ(x)], ρ, κ (LAM) E[λx :. e], ρ, κ E[ λx :. e, ρ ], ρ, κ (CALL) E[( λx :. e, ρ v)], ρ, κ e, (x, v) ρ, (E, ρ) κ where E [] (TAILCALL) ( λx :. e, ρ v), ρ, κ e, (x, v) ρ, κ (RET) v, ρ, (E, ρ ) κ E[v], ρ, κ (DELTA) E[(c v)], ρ, κ E[v ], ρ, κ where v = δ(c, v) (IFT) E[if true then e 2 else e 3 ], ρ, κ E[e 2 ], ρ, κ (IFF) E[if false then e 2 else e 3 ], ρ, κ E[e 3 ], ρ, κ (CSTAPP) E[( v 1 v 2 )], ρ, κ E[ (v v 2 )], ρ, κ (MERGE) E[ s], ρ, κ E[ s], ρ, κ where 7 = 5 1 (MERGEFAIL) E[ v], ρ, κ E[ fail : v], ρ, κ where 1 5 (TAILMERGE) e, ρ, ( E, ρ ) κ e, ρ, ( E, ρ ) κ where 7 = 5 2 (TAILFAIL) e, ρ, ( E, ρ ) κ e, ρ, ( fail : E, ρ ) κ where 2 5 Figure 4. Space-efficient dynamic semantics for the intermediate language λ?. 1. σ 1 1 σ 1 implies σ 2. σ 2 2 σ 2 and σ 1 1 σ 2, and 2. σ 2 2 σ 2 implies σ 1. σ 1 1 σ 1 and σ 1 1 σ 2. Proof sketch. Most of the rules that define the bisimulation relation 1 are simple congruence rules; but there is one interesting rule. The difference between 1 and 2 is that 1 generates wrapper functions, whereas 2 lets the casts build up. The following rule allows this difference with 1. s 1 1 s 2 (λx : (s x)) s 2 When a wrapped function (or cast function) is applied to some argument v 1 (or v 2, where v 1 1 v 2), then this difference goes away: ((λx : (s x)) v 1) (s v 1) and ( s 2 v 2) (s v 2) so the results are back to being bisimilar based on the congruence rules. Lemma 8 (Weak bisimulation between 2 and 3). If σ 2 2 σ 3 then 1. σ 2 2 σ 2 implies σ 3. σ 3 3 σ 3 and σ 2 2 σ 3, and 2. σ 3 3 σ 3 implies σ 2. σ 2 2 σ 2 and σ 2 2 σ 3. Proof sketch. The main difference between 2 and 3 is that 3 merges sequences of casts. The relation 2 relates a sequences of casts on the left side with a single cast on the right side, requiring the middle type of the cast on the right to be the least upper bound of the intermediate casts on the left. The cast on the right fails if and only if one of the casts on the left fails. Furthermore, /4/17

10 if they fail, they both blame the same cast and agree on whether it was the producer or consumer s fault. Theorem 4 (Equivalence). 1 and 3 are observationally equivalent. Proof. This is consequence of Lemmas 7 and 8 and the transitivity of bisimilarity. 5.3 Type safety The space-efficient semantics contains several subtle changes with respect to the straightforward semantics, including changes to the definition of values and cast errors, so we give more details of the proof here even though the outline of the proof remains the same. Lemma 9 (Canonical Forms). 1. If Γ v : int then v is an integer constant. 2. If Γ v : bool then v is true or false. 3. There is no simple value s such that Γ s :?. 4. If Γ s : 1 2 then s is what we call a simple function: either a closure or a functional constant. 5. If Γ v : 1 2 then v is either a simple function or it is a simple function s wrapped in a cast: s. Definition 4 (Preredex). A preredex is an expression in one of the following forms: x, (λx :. e), ( λx :. e, ρ v), ( v 1 v 2), ( v), ( fail : e), (if true then e 2 else e 3), or (if false then e 2 else e 3). Lemma 10 (Decomposition). If Γ e 1 : 1 then either e 1 is a value or there exists E, e 2, and 2 such that e 1 = E[e 2], Γ E : 2 1, Γ e 2 : 2, and e 2 is a preredex. Proof. The proof is by induction on the derivation of Γ e 1 : 1 and uses the Canonical Forms Lemma. Lemma 11 (Replacement). If Γ E : 1 2 and Γ e : 1 then Γ E[e] : 2. Proof. By induction on the derivation of Γ E : 1 2. Lemma 12 (Change of Environment for Values). If then for any Γ, Γ v :. Γ v : Proof. The proof is by induction on the derivation of Γ v :. Lemma 13 (Variable Lookup in Well-typed Environment). If Γ ρ and lookup(γ, x) = then there is a v such that lookup(ρ, x) = v and for any Γ, Γ v :. Proof. The proof is by induction on the derivation of Γ ρ and uses Lemma 12. With the introduction of the failure cast, the definition of a cast error changes to the following. Definition 5. A cast error is an expression of the form fail : v. Lemma 14 (Progress and Preservation). If σ then either 1. there is a σ such that σ σ and σ, or 2. σ is a final state, or 3. σ contains a cast error. Proof. The proof starts with some case analysis on the state, and then applies the Decomposition Lemma and proceeds by cases on preredexes. The case for returning from a function uses Lemma 12 and the case for merging a cast in tail-position relies on the property that if 3 = 1 2 then 1 3 and 2 3 and the transitivity of. The Replacement Lemma is used throughout to plug values back into contexts. The case for variable evaluation uses Lemma 13. The case for closure application uses Lemma 12 and the case for applying functional constants relies on the Canonical Forms Lemma for integers. Theorem 5 (Type Safety). If e e :, e, [], [] σ, and σ is a terminal state, then either 1) σ is a final state v, ρ, [] and v :, or 2) σ contains a cast error. Proof. The proof applies Lemma 1 and then proceeds by induction on the sequence of state transitions, using Lemma Blame safety To characterize well-typed regions, and to define safe casts, we use the subtyping relation defined in Section 2. Definition 6 (Well-typed Region). A well-typed region is an expression e 1 is such that Γ e 1 e 2 : and all of the casts in e 2 are safe. A safe cast has the form e 3 where 1 <: 2 and 1 <: 3. Definition 7 (Blame). Suppose Γ e 1 e 2 : and e 2, [], [] e 3, ρ, κ where e 3 contains a cast error fail : v where blame( 2) = (e 4, T, o). Then the blame for the cast error goes to the smallest expression e 5 e 1 such that Γ e 5 e 6 : and e 4 e 6. We now show that well-typed regions can be blamed for a cast error. The proof loosely follows that of Wadler and Findler (2007). Lemma 15 (Safe casts aren t to blame). Suppose e 1, [], [] e 2, ρ, κ where e contains a cast error fail : v and blame( 2) = (e 3, T, o). Then e 3 is not a safe cast. Proof sketch. The proof is by induction on the sequence of reductions. The main ideas are that a safe cast only gives rise to other safe casts and that subtyping implies consistency, so safe casts do not create cast errors. Theorem 6 (Well-typed regions can t be blamed). If e is a welltyped region then it can not be blamed for a cast error. Proof. By Lemma 15 and the definition of a well-typed region. 6. Related work The work on gradual typing gives a type theoretic foundation for the use of optional type annotations. Optional type annotations have appeared in many dynamic languages, such as Common LISP (Jr. 1982), Dylan (Feinberg et al. 1997), Cecil (Chambers and the Cecil Group 2004), extensions to Visual Basic.NET and C# (Meijer and Drayton 2004), Bigloo (Serrano 2002), and Strongtalk (Bracha and Griswold 1993). In all of these languages, adding type annotations brings some static checking and/or improves performance, but they do not formalize the semantics and guarantee that annotating all parameters in the program prevents any cast errors from occurring at run-time, as is provided by gradual typing /4/17

Gradual Typing for Functional Languages. Jeremy Siek and Walid Taha (presented by Lindsey Kuper)

Gradual Typing for Functional Languages. Jeremy Siek and Walid Taha (presented by Lindsey Kuper) Gradual Typing for Functional Languages Jeremy Siek and Walid Taha (presented by Lindsey Kuper) 1 Introduction 2 What we want Static and dynamic typing: both are useful! (If you re here, I assume you agree.)

More information

Gradual Typing with Inference

Gradual Typing with Inference Gradual Typing with Inference Jeremy Siek University of Colorado at Boulder joint work with Manish Vachharajani Overview Motivation Background Gradual Typing Unification-based inference Exploring the Solution

More information

Exploring the Design Space of Higher-Order Casts ; CU-CS

Exploring the Design Space of Higher-Order Casts ; CU-CS University of Colorado, Boulder CU Scholar Computer Science Technical Reports Computer Science Fall 10-1-2008 Exploring the Design Space of Higher-Order Casts ; CU-CS-1047-08 Jeremy Siek University of

More information

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

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages Harvard School of Engineering and Applied Sciences CS 152: Programming Languages Lecture 18 Thursday, April 3, 2014 1 Error-propagating semantics For the last few weeks, we have been studying type systems.

More information

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

CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Dan Grossman Spring 2011 CS152: Programming Languages Lecture 11 STLC Extensions and Related Topics Dan Grossman Spring 2011 Review e ::= λx. e x e e c v ::= λx. e c τ ::= int τ τ Γ ::= Γ, x : τ (λx. e) v e[v/x] e 1 e 1 e 1 e

More information

2 Blending static and dynamic typing

2 Blending static and dynamic typing 2 Blending static and dynamic typing We begin this chapter presenting a little bit of the history behind combining static and dynamic typing in the same language. Then, we introduce optional type systems

More information

1 Introduction. 3 Syntax

1 Introduction. 3 Syntax CS 6110 S18 Lecture 19 Typed λ-calculus 1 Introduction Type checking is a lightweight technique for proving simple properties of programs. Unlike theorem-proving techniques based on axiomatic semantics,

More information

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

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages Harvard School of Engineering and Applied Sciences CS 152: Programming Languages Lecture 24 Thursday, April 19, 2018 1 Error-propagating semantics For the last few weeks, we have been studying type systems.

More information

Tradeoffs. CSE 505: Programming Languages. Lecture 15 Subtyping. Where shall we add useful completeness? Where shall we add completeness?

Tradeoffs. CSE 505: Programming Languages. Lecture 15 Subtyping. Where shall we add useful completeness? Where shall we add completeness? Tradeoffs CSE 505: Programming Languages Lecture 15 Subtyping Zach Tatlock Autumn 2017 Desirable type system properties (desiderata): soundness - exclude all programs that get stuck completeness - include

More information

CS4215 Programming Language Implementation. Martin Henz

CS4215 Programming Language Implementation. Martin Henz CS4215 Programming Language Implementation Martin Henz Thursday 26 January, 2012 2 Chapter 4 The Language simpl In this chapter, we are exting the language epl in order to provide a more powerful programming

More information

Subsumption. Principle of safe substitution

Subsumption. Principle of safe substitution Recap on Subtyping Subsumption Some types are better than others, in the sense that a value of one can always safely be used where a value of the other is expected. Which can be formalized as by introducing:

More information

CS 6110 S11 Lecture 25 Typed λ-calculus 6 April 2011

CS 6110 S11 Lecture 25 Typed λ-calculus 6 April 2011 CS 6110 S11 Lecture 25 Typed λ-calculus 6 April 2011 1 Introduction Type checking is a lightweight technique for proving simple properties of programs. Unlike theorem-proving techniques based on axiomatic

More information

The gradual typing approach to mixing static and dynamic typing

The gradual typing approach to mixing static and dynamic typing 1 / 38 The gradual typing approach to mixing static and dynamic typing Jeremy G. Siek University of Colorado = Indiana University TFP 2013 at Provo, Utah, May 2013 The Goals of Gradual Typing Enjoy the

More information

Review. CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Let bindings (CBV) Adding Stuff. Booleans and Conditionals

Review. CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Let bindings (CBV) Adding Stuff. Booleans and Conditionals Review CS152: Programming Languages Lecture 11 STLC Extensions and Related Topics e ::= λx. e x ee c v ::= λx. e c (λx. e) v e[v/x] e 1 e 2 e 1 e 2 τ ::= int τ τ Γ ::= Γ,x : τ e 2 e 2 ve 2 ve 2 e[e /x]:

More information

Abstract register machines Lecture 23 Tuesday, April 19, 2016

Abstract register machines Lecture 23 Tuesday, April 19, 2016 Harvard School of Engineering and Applied Sciences CS 152: Programming Languages Lecture 23 Tuesday, April 19, 2016 1 Why abstract machines? So far in the class, we have seen a variety of language features.

More information

CS558 Programming Languages

CS558 Programming Languages CS558 Programming Languages Fall 2016 Lecture 7a Andrew Tolmach Portland State University 1994-2016 Values and Types We divide the universe of values according to types A type is a set of values and a

More information

Simply-Typed Lambda Calculus

Simply-Typed Lambda Calculus #1 Simply-Typed Lambda Calculus #2 Back to School What is operational semantics? When would you use contextual (small-step) semantics? What is denotational semantics? What is axiomatic semantics? What

More information

6.001 Notes: Section 8.1

6.001 Notes: Section 8.1 6.001 Notes: Section 8.1 Slide 8.1.1 In this lecture we are going to introduce a new data type, specifically to deal with symbols. This may sound a bit odd, but if you step back, you may realize that everything

More information

CS 6110 S14 Lecture 1 Introduction 24 January 2014

CS 6110 S14 Lecture 1 Introduction 24 January 2014 CS 6110 S14 Lecture 1 Introduction 24 January 2014 1 Introduction What is a program? Is it just something that tells the computer what to do? Yes, but there is much more to it than that. The basic expressions

More information

Polymorphic lambda calculus Princ. of Progr. Languages (and Extended ) The University of Birmingham. c Uday Reddy

Polymorphic lambda calculus Princ. of Progr. Languages (and Extended ) The University of Birmingham. c Uday Reddy 06-02552 Princ. of Progr. Languages (and Extended ) The University of Birmingham Spring Semester 2016-17 School of Computer Science c Uday Reddy2016-17 Handout 6: Polymorphic Type Systems 1. Polymorphic

More information

Lecture 9: Typed Lambda Calculus

Lecture 9: Typed Lambda Calculus Advanced Topics in Programming Languages Spring Semester, 2012 Lecture 9: Typed Lambda Calculus May 8, 2012 Lecturer: Mooly Sagiv Scribe: Guy Golan Gueta and Shachar Itzhaky 1 Defining a Type System for

More information

CS-XXX: Graduate Programming Languages. Lecture 9 Simply Typed Lambda Calculus. Dan Grossman 2012

CS-XXX: Graduate Programming Languages. Lecture 9 Simply Typed Lambda Calculus. Dan Grossman 2012 CS-XXX: Graduate Programming Languages Lecture 9 Simply Typed Lambda Calculus Dan Grossman 2012 Types Major new topic worthy of several lectures: Type systems Continue to use (CBV) Lambda Caluclus as our

More information

6.001 Notes: Section 6.1

6.001 Notes: Section 6.1 6.001 Notes: Section 6.1 Slide 6.1.1 When we first starting talking about Scheme expressions, you may recall we said that (almost) every Scheme expression had three components, a syntax (legal ways of

More information

CS 6110 S11 Lecture 12 Naming and Scope 21 February 2011

CS 6110 S11 Lecture 12 Naming and Scope 21 February 2011 CS 6110 S11 Lecture 12 Naming and Scope 21 February 2011 In this lecture we introduce the topic of scope in the context of the λ-calculus and define translations from λ-cbv to FL for the two most common

More information

Interlanguage Migration: From Scripts to Programs

Interlanguage Migration: From Scripts to Programs Interlanguage Migration: From Scripts to Programs Sam Tobin-Hochstadt Northeastern University Boston, MA samth@ccs.neu.edu Matthias Felleisen Northeastern University Boston, MA matthias@ccs.neu.edu ABSTRACT

More information

Well-typed programs can t be blamed

Well-typed programs can t be blamed Well-typed programs can t be blamed Philip Wadler University of Edinburgh Robert Bruce Findler University of Chicago Abstract We show how contracts with blame fit naturally with recent work on hybrid types

More information

3.4 Deduction and Evaluation: Tools Conditional-Equational Logic

3.4 Deduction and Evaluation: Tools Conditional-Equational Logic 3.4 Deduction and Evaluation: Tools 3.4.1 Conditional-Equational Logic The general definition of a formal specification from above was based on the existence of a precisely defined semantics for the syntax

More information

COS 320. Compiling Techniques

COS 320. Compiling Techniques Topic 5: Types COS 320 Compiling Techniques Princeton University Spring 2016 Lennart Beringer 1 Types: potential benefits (I) 2 For programmers: help to eliminate common programming mistakes, particularly

More information

4.5 Pure Linear Functional Programming

4.5 Pure Linear Functional Programming 4.5 Pure Linear Functional Programming 99 4.5 Pure Linear Functional Programming The linear λ-calculus developed in the preceding sections can serve as the basis for a programming language. The step from

More information

Lecture Notes on Data Representation

Lecture Notes on Data Representation Lecture Notes on Data Representation 15-814: Types and Programming Languages Frank Pfenning Lecture 9 Tuesday, October 2, 2018 1 Introduction In this lecture we ll see our type system in action. In particular

More information

CSCI B522 Lecture 11 Naming and Scope 8 Oct, 2009

CSCI B522 Lecture 11 Naming and Scope 8 Oct, 2009 CSCI B522 Lecture 11 Naming and Scope 8 Oct, 2009 Lecture notes for CS 6110 (Spring 09) taught by Andrew Myers at Cornell; edited by Amal Ahmed, Fall 09. 1 Static vs. dynamic scoping The scope of a variable

More information

Note that in this definition, n + m denotes the syntactic expression with three symbols n, +, and m, not to the number that is the sum of n and m.

Note that in this definition, n + m denotes the syntactic expression with three symbols n, +, and m, not to the number that is the sum of n and m. CS 6110 S18 Lecture 8 Structural Operational Semantics and IMP Today we introduce a very simple imperative language, IMP, along with two systems of rules for evaluation called small-step and big-step semantics.

More information

CMSC 336: Type Systems for Programming Languages Lecture 5: Simply Typed Lambda Calculus Acar & Ahmed January 24, 2008

CMSC 336: Type Systems for Programming Languages Lecture 5: Simply Typed Lambda Calculus Acar & Ahmed January 24, 2008 CMSC 336: Type Systems for Programming Languages Lecture 5: Simply Typed Lambda Calculus Acar & Ahmed January 24, 2008 Contents 1 Solution to the Exercise 1 1.1 Semantics for lambda calculus.......................

More information

Lecture Notes on Program Equivalence

Lecture Notes on Program Equivalence Lecture Notes on Program Equivalence 15-312: Foundations of Programming Languages Frank Pfenning Lecture 24 November 30, 2004 When are two programs equal? Without much reflection one might say that two

More information

Programming Languages

Programming Languages CSE 230: Winter 2008 Principles of Programming Languages Ocaml/HW #3 Q-A Session Push deadline = Mar 10 Session Mon 3pm? Lecture 15: Type Systems Ranjit Jhala UC San Diego Why Typed Languages? Development

More information

Interlanguage Migration

Interlanguage Migration Interlanguage Migration From Scripts to Programs Sam Tobin-Hochstadt and Matthias Felleisen Northeastern University DLS 2006 1 A Story 2 About a programmer 3 Who needed to manage his budget 4 And so, he

More information

Pierce Ch. 3, 8, 11, 15. Type Systems

Pierce Ch. 3, 8, 11, 15. Type Systems Pierce Ch. 3, 8, 11, 15 Type Systems Goals Define the simple language of expressions A small subset of Lisp, with minor modifications Define the type system of this language Mathematical definition using

More information

Outline. Introduction Concepts and terminology The case for static typing. Implementing a static type system Basic typing relations Adding context

Outline. Introduction Concepts and terminology The case for static typing. Implementing a static type system Basic typing relations Adding context Types 1 / 15 Outline Introduction Concepts and terminology The case for static typing Implementing a static type system Basic typing relations Adding context 2 / 15 Types and type errors Type: a set of

More information

Subtyping. Lecture 13 CS 565 3/27/06

Subtyping. Lecture 13 CS 565 3/27/06 Subtyping Lecture 13 CS 565 3/27/06 Polymorphism Different varieties of polymorphism: Parametric (ML) type variables are abstract, and used to encode the fact that the same term can be used in many different

More information

Mutable References. Chapter 1

Mutable References. Chapter 1 Chapter 1 Mutable References In the (typed or untyped) λ-calculus, or in pure functional languages, a variable is immutable in that once bound to a value as the result of a substitution, its contents never

More information

Concepts of programming languages

Concepts of programming languages Concepts of programming languages Lecture 5 Wouter Swierstra 1 Announcements Submit your project proposal to me by email on Friday; The presentation schedule in now online Exercise session after the lecture.

More information

Consistent Subtyping for All

Consistent Subtyping for All Consistent Subtyping for All Ningning Xie Xuan Bi Bruno C. d. S. Oliveira 11 May, 2018 The University of Hong Kong 1 Background There has been ongoing debate about which language paradigm, static typing

More information

Types for References, Exceptions and Continuations. Review of Subtyping. Γ e:τ τ <:σ Γ e:σ. Annoucements. How s the midterm going?

Types for References, Exceptions and Continuations. Review of Subtyping. Γ e:τ τ <:σ Γ e:σ. Annoucements. How s the midterm going? Types for References, Exceptions and Continuations Annoucements How s the midterm going? Meeting 21, CSCI 5535, Spring 2009 2 One-Slide Summary Review of Subtyping If τ is a subtype of σ then any expression

More information

A Typed Lambda Calculus for Input Sanitation

A Typed Lambda Calculus for Input Sanitation A Typed Lambda Calculus for Input Sanitation Nathan Fulton Carthage College nfulton@carthage.edu April 11, 2013 Abstract Programmers often wish to validate or sanitize user input. One common approach to

More information

Formal Systems and their Applications

Formal Systems and their Applications Formal Systems and their Applications Dave Clarke (Dave.Clarke@cs.kuleuven.be) Acknowledgment: these slides are based in part on slides from Benjamin Pierce and Frank Piessens 1 Course Overview Introduction

More information

From IMP to Java. Andreas Lochbihler. parts based on work by Gerwin Klein and Tobias Nipkow ETH Zurich

From IMP to Java. Andreas Lochbihler. parts based on work by Gerwin Klein and Tobias Nipkow ETH Zurich From IMP to Java Andreas Lochbihler ETH Zurich parts based on work by Gerwin Klein and Tobias Nipkow 2015-07-14 1 Subtyping 2 Objects and Inheritance 3 Multithreading 1 Subtyping 2 Objects and Inheritance

More information

(Refer Slide Time: 4:00)

(Refer Slide Time: 4:00) Principles of Programming Languages Dr. S. Arun Kumar Department of Computer Science & Engineering Indian Institute of Technology, Delhi Lecture - 38 Meanings Let us look at abstracts namely functional

More information

Programming Languages Third Edition

Programming Languages Third Edition Programming Languages Third Edition Chapter 12 Formal Semantics Objectives Become familiar with a sample small language for the purpose of semantic specification Understand operational semantics Understand

More information

CS558 Programming Languages

CS558 Programming Languages CS558 Programming Languages Winter 2017 Lecture 7b Andrew Tolmach Portland State University 1994-2017 Values and Types We divide the universe of values according to types A type is a set of values and

More information

CMSC 330: Organization of Programming Languages

CMSC 330: Organization of Programming Languages CMSC 330: Organization of Programming Languages Type Systems, Names and Binding CMSC 330 - Spring 2013 1 Topics Covered Thus Far! Programming languages Ruby OCaml! Syntax specification Regular expressions

More information

Goal. CS152: Programming Languages. Lecture 15 Parametric Polymorphism. What the Library Likes. What The Client Likes. Start simpler.

Goal. CS152: Programming Languages. Lecture 15 Parametric Polymorphism. What the Library Likes. What The Client Likes. Start simpler. Goal Understand what this interface means and why it matters: CS152: Programming Languages Lecture 15 Parametric Polymorphism Dan Grossman Spring 2011 type a mylist; val mt_list : a mylist val cons : a

More information

Runtime Behavior of Conversion Interpretation of Subtyping

Runtime Behavior of Conversion Interpretation of Subtyping Runtime Behavior of Conversion Interpretation of Subtyping Yasuhiko Minamide Institute of Information Sciences and Electronics University of Tsukuba and PRESTO, JST minamide@is.tsukuba.ac.jp Abstract.

More information

Part III. Chapter 15: Subtyping

Part III. Chapter 15: Subtyping Part III Chapter 15: Subtyping Subsumption Subtype relation Properties of subtyping and typing Subtyping and other features Intersection and union types Subtyping Motivation With the usual typing rule

More information

Topics Covered Thus Far CMSC 330: Organization of Programming Languages

Topics Covered Thus Far CMSC 330: Organization of Programming Languages Topics Covered Thus Far CMSC 330: Organization of Programming Languages Names & Binding, Type Systems Programming languages Ruby Ocaml Lambda calculus Syntax specification Regular expressions Context free

More information

The Polymorphic Blame Calculus and Parametricity

The Polymorphic Blame Calculus and Parametricity 1 / 31 The Polymorphic Blame Calculus and Parametricity Jeremy G. Siek Indiana University, Bloomington University of Strathclyde August 2015 2 / 31 Integrating static and dynamic typing Static Dynamic

More information

Space-Efficient Gradual Typing

Space-Efficient Gradual Typing Space-Efficient Gradual Typing David Herman 1, Aaron Tomb 2, and Cormac Flanagan 2 1 Northeastern University 2 University of California, Santa Cruz Abstract Gradual type systems offer a smooth continuum

More information

CMSC 631 Program Analysis and Understanding. Dynamic Typing, Contracts, and Gradual Typing

CMSC 631 Program Analysis and Understanding. Dynamic Typing, Contracts, and Gradual Typing CMSC 631 Program Analysis and Understanding Dynamic Typing, Contracts, and Gradual Typing Static vs. Dynamic Typing Languages with Static Typing Examples: Ocaml, Java, C#, Scala, Haskell Typechecker proves

More information

CSCI-GA Scripting Languages

CSCI-GA Scripting Languages CSCI-GA.3033.003 Scripting Languages 12/02/2013 OCaml 1 Acknowledgement The material on these slides is based on notes provided by Dexter Kozen. 2 About OCaml A functional programming language All computation

More information

Gradual Typing for Mutable Objects

Gradual Typing for Mutable Objects Gradual Typing for Mutable Objects Jeremy G. Siek 1, Michael M. Vitousek 2, and Shashank Bharadwaj 1 1 Department of Electrical, Computer, and Energy Engineering 2 Department of Computer Science University

More information

CIS 500 Software Foundations Fall September 25

CIS 500 Software Foundations Fall September 25 CIS 500 Software Foundations Fall 2006 September 25 The Lambda Calculus The lambda-calculus If our previous language of arithmetic expressions was the simplest nontrivial programming language, then the

More information

More Lambda Calculus and Intro to Type Systems

More Lambda Calculus and Intro to Type Systems More Lambda Calculus and Intro to Type Systems Plan Heavy Class Participation Thus, wake up! Lambda Calculus How is it related to real life? Encodings Fixed points Type Systems Overview Static, Dyamic

More information

Tracing Ambiguity in GADT Type Inference

Tracing Ambiguity in GADT Type Inference Tracing Ambiguity in GADT Type Inference ML Workshop 2012, Copenhagen Jacques Garrigue & Didier Rémy Nagoya University / INRIA Garrigue & Rémy Tracing ambiguity 1 Generalized Algebraic Datatypes Algebraic

More information

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

Chapter 13: Reference. Why reference Typing Evaluation Store Typings Safety Notes Chapter 13: Reference Why reference Typing Evaluation Store Typings Safety Notes References Computational Effects Also known as side effects. A function or expression is said to have a side effect if,

More information

Once Upon a Polymorphic Type

Once Upon a Polymorphic Type Once Upon a Polymorphic Type Keith Wansbrough Computer Laboratory University of Cambridge kw217@cl.cam.ac.uk http://www.cl.cam.ac.uk/users/kw217/ Simon Peyton Jones Microsoft Research Cambridge 20 January,

More information

Type Systems. Pierce Ch. 3, 8, 11, 15 CSE

Type Systems. Pierce Ch. 3, 8, 11, 15 CSE Type Systems Pierce Ch. 3, 8, 11, 15 CSE 6341 1 A Simple Language ::= true false if then else 0 succ pred iszero Simple untyped expressions Natural numbers encoded as succ succ

More information

Formal semantics of loosely typed languages. Joep Verkoelen Vincent Driessen

Formal semantics of loosely typed languages. Joep Verkoelen Vincent Driessen Formal semantics of loosely typed languages Joep Verkoelen Vincent Driessen June, 2004 ii Contents 1 Introduction 3 2 Syntax 5 2.1 Formalities.............................. 5 2.2 Example language LooselyWhile.................

More information

Lecture 13: Subtyping

Lecture 13: Subtyping Lecture 13: Subtyping Polyvios Pratikakis Computer Science Department, University of Crete Type Systems and Programming Languages Pratikakis (CSD) Subtyping CS546, 2018-2019 1 / 15 Subtyping Usually found

More information

Programming Languages Lecture 14: Sum, Product, Recursive Types

Programming Languages Lecture 14: Sum, Product, Recursive Types CSE 230: Winter 200 Principles of Programming Languages Lecture 4: Sum, Product, Recursive Types The end is nigh HW 3 No HW 4 (= Final) Project (Meeting + Talk) Ranjit Jhala UC San Diego Recap Goal: Relate

More information

Type Checking in COOL (II) Lecture 10

Type Checking in COOL (II) Lecture 10 Type Checking in COOL (II) Lecture 10 1 Lecture Outline Type systems and their expressiveness Type checking with SELF_TYPE in COOL Error recovery in semantic analysis 2 Expressiveness of Static Type Systems

More information

Typed Lambda Calculus and Exception Handling

Typed Lambda Calculus and Exception Handling Typed Lambda Calculus and Exception Handling Dan Zingaro zingard@mcmaster.ca McMaster University Typed Lambda Calculus and Exception Handling p. 1/2 Untyped Lambda Calculus Goal is to introduce typing

More information

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

Topics Covered Thus Far. CMSC 330: Organization of Programming Languages. Language Features Covered Thus Far. Programming Languages Revisited CMSC 330: Organization of Programming Languages Type Systems, Names & Binding Topics Covered Thus Far Programming languages Syntax specification Regular expressions Context free grammars Implementation

More information

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

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages Harvard School of Engineering and Applied Sciences CS 152: Programming Languages Lecture 14 Tuesday, March 24, 2015 1 Parametric polymorphism Polymorph means many forms. Polymorphism is the ability of

More information

Types. Type checking. Why Do We Need Type Systems? Types and Operations. What is a type? Consensus

Types. Type checking. Why Do We Need Type Systems? Types and Operations. What is a type? Consensus Types Type checking What is a type? The notion varies from language to language Consensus A set of values A set of operations on those values Classes are one instantiation of the modern notion of type

More information

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

Programming Language Features. CMSC 330: Organization of Programming Languages. Turing Completeness. Turing Machine. CMSC 330: Organization of Programming Languages Lambda Calculus Programming Language Features Many features exist simply for convenience Multi-argument functions foo ( a, b, c ) Ø Use currying or tuples

More information

CMSC 330: Organization of Programming Languages

CMSC 330: Organization of Programming Languages CMSC 330: Organization of Programming Languages Lambda Calculus CMSC 330 1 Programming Language Features Many features exist simply for convenience Multi-argument functions foo ( a, b, c ) Ø Use currying

More information

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler Front-End

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler Front-End Outline Semantic Analysis The role of semantic analysis in a compiler A laundry list of tasks Scope Static vs. Dynamic scoping Implementation: symbol tables Types Static analyses that detect type errors

More information

Programming Languages Fall 2014

Programming Languages Fall 2014 Programming Languages Fall 2014 Lecture 7: Simple Types and Simply-Typed Lambda Calculus Prof. Liang Huang huang@qc.cs.cuny.edu 1 Types stuck terms? how to fix it? 2 Plan First I For today, we ll go back

More information

CMSC 330: Organization of Programming Languages

CMSC 330: Organization of Programming Languages CMSC 330: Organization of Programming Languages Operational Semantics CMSC 330 Summer 2018 1 Formal Semantics of a Prog. Lang. Mathematical description of the meaning of programs written in that language

More information

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

The University of Nottingham SCHOOL OF COMPUTER SCIENCE A LEVEL 4 MODULE, SPRING SEMESTER MATHEMATICAL FOUNDATIONS OF PROGRAMMING ANSWERS The University of Nottingham SCHOOL OF COMPUTER SCIENCE A LEVEL 4 MODULE, SPRING SEMESTER 2012 2013 MATHEMATICAL FOUNDATIONS OF PROGRAMMING ANSWERS Time allowed TWO hours Candidates may complete the front

More information

Lecture 5: The Untyped λ-calculus

Lecture 5: The Untyped λ-calculus Lecture 5: The Untyped λ-calculus Syntax and basic examples Polyvios Pratikakis Computer Science Department, University of Crete Type Systems and Static Analysis Pratikakis (CSD) Untyped λ-calculus I CS49040,

More information

Chapter 2 The Language PCF

Chapter 2 The Language PCF Chapter 2 The Language PCF We will illustrate the various styles of semantics of programming languages with an example: the language PCF Programming language for computable functions, also called Mini-ML.

More information

CONVENTIONAL EXECUTABLE SEMANTICS. Grigore Rosu CS522 Programming Language Semantics

CONVENTIONAL EXECUTABLE SEMANTICS. Grigore Rosu CS522 Programming Language Semantics CONVENTIONAL EXECUTABLE SEMANTICS Grigore Rosu CS522 Programming Language Semantics Conventional Semantic Approaches A language designer should understand the existing design approaches, techniques and

More information

A Type System for Functional Traversal-Based Aspects

A Type System for Functional Traversal-Based Aspects A Type System for Functional Traversal-Based Aspects Bryan Chadwick College of Computer & Information Science Northeastern University, 360 Huntington Avenue Boston, Massachusetts 02115 USA chadwick@ccs.neu.edu

More information

CONVENTIONAL EXECUTABLE SEMANTICS. Grigore Rosu CS422 Programming Language Semantics

CONVENTIONAL EXECUTABLE SEMANTICS. Grigore Rosu CS422 Programming Language Semantics CONVENTIONAL EXECUTABLE SEMANTICS Grigore Rosu CS422 Programming Language Semantics Conventional Semantic Approaches A language designer should understand the existing design approaches, techniques and

More information

Part III Chapter 15: Subtyping

Part III Chapter 15: Subtyping Part III Chapter 15: Subtyping Subsumption Subtype relation Properties of subtyping and typing Subtyping and other features Intersection and union types Subtyping Motivation With the usual typing rule

More information

Lambda Calculus: Implementation Techniques and a Proof. COS 441 Slides 15

Lambda Calculus: Implementation Techniques and a Proof. COS 441 Slides 15 Lambda Calculus: Implementation Techniques and a Proof COS 441 Slides 15 Last Time: The Lambda Calculus A language of pure functions: values e ::= x \x.e e e v ::= \x.e With a call-by-value operational

More information

The role of semantic analysis in a compiler

The role of semantic analysis in a compiler Semantic Analysis Outline The role of semantic analysis in a compiler A laundry list of tasks Scope Static vs. Dynamic scoping Implementation: symbol tables Types Static analyses that detect type errors

More information

Let Arguments Go First

Let Arguments Go First Let Arguments Go First Ningning Xie and Bruno C. d. S. Oliveira The University of Hong Kong {nnxie,bruno}@cs.hku.hk Abstract. Bi-directional type checking has proved to be an extremely useful and versatile

More information

1. true / false By a compiler we mean a program that translates to code that will run natively on some machine.

1. true / false By a compiler we mean a program that translates to code that will run natively on some machine. 1. true / false By a compiler we mean a program that translates to code that will run natively on some machine. 2. true / false ML can be compiled. 3. true / false FORTRAN can reasonably be considered

More information

Type Systems Winter Semester 2006

Type Systems Winter Semester 2006 Type Systems Winter Semester 2006 Week 4 November 8 November 15, 2006 - version 1.1 The Lambda Calculus The lambda-calculus If our previous language of arithmetic expressions was the simplest nontrivial

More information

Project 6 Due 11:59:59pm Thu, Dec 10, 2015

Project 6 Due 11:59:59pm Thu, Dec 10, 2015 Project 6 Due 11:59:59pm Thu, Dec 10, 2015 Updates None yet. Introduction In this project, you will add a static type checking system to the Rube programming language. Recall the formal syntax for Rube

More information

Foundations. Yu Zhang. Acknowledgement: modified from Stanford CS242

Foundations. Yu Zhang. Acknowledgement: modified from Stanford CS242 Spring 2013 Foundations Yu Zhang Acknowledgement: modified from Stanford CS242 https://courseware.stanford.edu/pg/courses/317431/ Course web site: http://staff.ustc.edu.cn/~yuzhang/fpl Reading Concepts

More information

CS 242. Fundamentals. Reading: See last slide

CS 242. Fundamentals. Reading: See last slide CS 242 Fundamentals Reading: See last slide Syntax and Semantics of Programs Syntax The symbols used to write a program Semantics The actions that occur when a program is executed Programming language

More information

The story so far. Elements of Programming Languages. Pairs in various languages. Pairs

The story so far. Elements of Programming Languages. Pairs in various languages. Pairs Elements of Programming Languages Lecture 6: Data structures James Cheney University of Edinburgh October 9, 2017 The story so far We ve now covered the main ingredients of any programming language: Abstract

More information

The Substitution Model

The Substitution Model The Substitution Model Prof. Clarkson Fall 2017 Today s music: Substitute by The Who Review Previously in 3110: simple interpreter for expression language abstract syntax tree (AST) evaluation based on

More information

Joint Entity Resolution

Joint Entity Resolution Joint Entity Resolution Steven Euijong Whang, Hector Garcia-Molina Computer Science Department, Stanford University 353 Serra Mall, Stanford, CA 94305, USA {swhang, hector}@cs.stanford.edu No Institute

More information

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

Tail Calls. CMSC 330: Organization of Programming Languages. Tail Recursion. Tail Recursion (cont d) Names and Binding. Tail Recursion (cont d) CMSC 330: Organization of Programming Languages Tail Calls A tail call is a function call that is the last thing a function does before it returns let add x y = x + y let f z = add z z (* tail call *)

More information

Harvard School of Engineering and Applied Sciences Computer Science 152

Harvard School of Engineering and Applied Sciences Computer Science 152 Harvard School of Engineering and Applied Sciences Computer Science 152 Lecture 17 Tuesday, March 30, 2010 1 Polymorph means many forms. Polymorphism is the ability of code to be used on values of different

More information

Lecture 3: Recursion; Structural Induction

Lecture 3: Recursion; Structural Induction 15-150 Lecture 3: Recursion; Structural Induction Lecture by Dan Licata January 24, 2012 Today, we are going to talk about one of the most important ideas in functional programming, structural recursion

More information

Featherweight Java (FJ)

Featherweight Java (FJ) x = 1 let x = 1 in... x(1).!x(1) x.set(1) Programming Language Theory Featherweight Java (FJ) Ralf Lämmel This lecture is based on David Walker s lecture: Computer Science 441, Programming Languages, Princeton

More information