Type Variables in Patterns

Total Page:16

File Type:pdf, Size:1020Kb

Type Variables in Patterns Type variables in patterns Richard A. Eisenberg Joachim Breitner Simon Peyton Jones Bryn Mawr College University of Pennsylvania Microsoft Research Bryn Mawr, PA, USA Philadelphia, PA, USA Cambridge, UK [email protected] [email protected] [email protected] Abstract need a way to name such types. The obvious way to address For many years, GHC has implemented an extension to this challenge is by providing language support for lexically Haskell that allows type variables to be bound in type sig- scoped type variables. GHC has long supported scoped type natures and patterns, and to scope over terms. This exten- variables: the ScopedTypeVariables extension is very popular, sion was never properly specified. We rectify that oversight and 29% of Haskell packages on Hackage use it. But it has here. With the formal specification in hand, the otherwise- never been formally specified! Moreover, as we shall see, it labyrinthine path toward a design for binding type vari- is in any case inadequate to the task. In this paper we fix ables in patterns becomes blindingly clear. We thus extend both problems, making the following contributions: ScopedTypeVariables to bind type variables explicitly, obvi- ating the Proxy workaround to the dustbin of history. In the days of Haskell98, scoped type variables were • 1 Introduction seldom crucial. Through a series of examples we show Haskell allows the programmer to write a type signature for a that, as Haskell’s type system has grown more sophis- definition or expression, both as machine-checked documen- ticated, the need for scoped type variables has become tation, and to resolve ambiguity (Section 2.1). For example, acute (Section 2), while at the same time GHC’s exist- ing support for them has become more visibly inade- prefix :: a a a → [[ ]] → [[ ]] quate (Section 3). prefixx yss = map xcons yss To fix these inadequacies, we describe visible type ap- • where xcons ys = x : ys plication in patterns, a natural extension to GHC’s ex- Sadly, it is not always possible to write such a type signature. isting visible type applications from terms to patterns For example, to give a signature for xcons we might try: (Section 4). We give the first formal specification of scoped type prefix :: a a a • → [[ ]] → [[ ]] variables for Haskell, formalizing the folklore, and pro- prefixx yss = map xcons yss viding a firm foundation for both design and imple- where xcons :: a a [ ] → [ ] mentation (Section 5). xcons ys = x : ys As part of this specification, we offer a new and simpler • But Haskell98’s scoping rules specify that the a in the signa- typing judgment for GADT pattern matching (Sec- ture for xcons is locally quantified, thus: xcons :: a. a tion 5.3), which treats uniformly the universal and [ ] → a . That is not what we want! We want the a in∀ the sig- existential variables of a data constructor. [ ] nature for xcons to mean “the universally quantified type variable for prefix”, and Haskell98 provides no way to do that. The inability to supply a type signature for xcons might arXiv:1806.03476v1 [cs.PL] 9 Jun 2018 seem merely inconvenient, but it is just the tip of an iceberg. 2 Motivation and background Haskell uses type inference to infer types, and that is a won- 2.1 The need for type annotations derful thing. However, insisting on complete type inference— One of the magical properties of ML-family languages, in- that is, the ability to infer types for any well-typed program cluding Haskell, is that type inference allows us to write with no help from the programmer—places serious limits many programs with no type annotations whatsoever. In on the expressiveness of the type system. GHC’s version of practice, however, Haskell programs contain many user- Haskell has gone far beyond these limits, and fundamentally written type signatures, for two main reasons. relies on programmer-supplied annotations to guide type First, the type of a function can be extremely helpful as doc- inference. As some examples, see the work of Peyton Jones umentation, with the advantage that it is machine-checked et al. [2007], Vytiniotis et al. [2011], or Eisenberg et al. [2016]. documentation. Almost all programmers regard it as good So the challenge we address is this: it should be possible practice to provide a signature for every top-level function. for the programmer to write an explicit type signature for any Indeed, GHC has a warning flag, -Wmissing-signatures, sub-term of the program. To do so, some type signatures must which enforces this convention. refer to a type that is already in the static environment, so we 2 Richard A. Eisenberg, Joachim Breitner, and Simon Peyton Jones show :: Showa a String a really is Int. GHC can use this fact during type check- ⇒ → read :: Reada String a ing the right-hand side of a function, like this: ⇒ → ++ :: a a a matchG :: Ga a ( ) [ ] → [ ] → [ ] → concat :: a a = [[ ]] → [ ] matchG MkInt 5 matchG MkFun = +10 ( ) Figure 1. Types of standard functions Again, however, matchG will only type-check if it is given a signature; see Schrijvers et al. [2009] for details. Second, as Haskell’s type system becomes increasingly Ambiguous types. Consider • expressive, complete type inference becomes intractable, and Fa the type system necessarily relies on programmer-supplied type family ambig :: Typeablea Fa Int type annotations. Here are some examples: ⇒ → Type-class ambiguity is present even in Haskell 98. test :: Char Int • → Consider1: testx = ambigx normalize :: String String In test GHC must decide at what type to call ambig; → normalizes = show reads that is, what type should instantiate the a in ambig’s ( ) type. Any choice a = τ must ensure that F τ Char This function parses a string to a value of some type, ∼ but, because F might not be injective, that does not tell and then turns that value back into a string. But noth- us what a should be. A type signature is not enough to ing in the code specifies that type, so the programmer resolve this case; we need a different form of type an- must disambiguate. One way to do so is to provide notation, namely visible type application (Section 2.3). a type signature that specifies the result type of the reads call, thus: There is a general pattern here: as the type system becomes more expressive, the type inference needs more guidance. normalizes = show reads :: Int ( ) Moreover, that guidance is extremely informative to the Polymorphic recursion. In ML, recursive calls to a func- programmer, as well as to the compiler. • tion must be at monomorphic type, but Haskell has always supported polymorphic recursion, provided 2.2 Support for scoped type variables the function has a type signature. For example: Given the increasing importance of type annotations, a good principle is this: it should be possible to specify, via a type data Ta = Leafa Node T a T a | ( [ ]) ( [ ]) signature, the type of any sub-expression or any let-binding. leaves :: Ta a → [ ] Alas, as shown in the introduction, Haskell98 supports only leaves Leafx = x ( ) [ ] closed type signatures, so there are useful type signatures leaves Node t1 t2 = concat leaves t1 ++ leaves t2 that we simply cannot write. ( ) ( ) Higher-rank types [Peyton Jones et al. 2007]. Consider The key deficiency in Haskell98 is that it provides noway • to bring type variables into scope. GHC has recognized this f :: a. a a Char , Bool ( [ ] → [ ]) → ([ ] [ ]) need for many years, and the ScopedTypeVariables extension fg =∀ g "Hello", g True, False ( [ ]) offers two ways to bring a type variable into scope: Here the type of g is polymorphic, so it can be applied Binding in a declaration signature. Since 2004 GHC • to lists of different type. The type signature is essential allows you to write to specify the type of the argument g; without it, f will prefix :: a. a a a be rejected. ∀ → [[ ]] → [[ ]] Generalized algebraic data types [Schrijvers et al. 2009]. prefixx yss = map xcons yss • where xcons :: a a The popular GADTs extension to GHC allows pattern [ ] → [ ] matching to refine the type information available in xcons ys = x : ys the right hand side of an equation. Here is an example: The explicit “ ” brings a into scope in the rest of the data Ga where type signature∀ (of course), but it also brings a into MkInt :: G Int scope in the body of the named function, prefix in this MkFun :: G Int Int case. The rule is a bit strange, because the definition ( → ) of prefix is not syntactically “under” the , and indeed When we learn that a value g :: Ga is actually the the signature can be written far away from∀ the actual constructor MkInt, then we simultaneously learn that binding. But in practice the rule works well, and we 1 Figure 1 gives the types of standard functions, such as read and show. take it as-is for the purposes of this paper. Type variables in patterns 3 Pattern signatures: binding a type variable in a pattern. 3.1 The binding structure of a pattern signature • For even longer, since 1998, GHC has allowed you to A pattern signature may bind a type variable, but it may also write this: mention a type variable that is already in scope. For example, we may write prefix x :: b yss = map xcons yss ( ) prefix x :: a yss = map xcons yss where xcons :: b b ( ) [ ] → [ ] where xcons ys :: a = x : ys xcons ys = x : ys ( [ ]) Here, the pattern signature x :: a binds a (as well as x), but Here, we bind the type variable b in the pattern x :: b , ( ) ( ) the pattern signature ys :: a simply mentions a (which is and this binding scopes over the body of the binding.
Recommended publications
  • ML Module Mania: a Type-Safe, Separately Compiled, Extensible Interpreter
    ML Module Mania: A Type-Safe, Separately Compiled, Extensible Interpreter The Harvard community has made this article openly available. Please share how this access benefits you. Your story matters Citation Ramsey, Norman. 2005. ML Module Mania: A Type-Safe, Separately Compiled, Extensible Interpreter. Harvard Computer Science Group Technical Report TR-11-05. Citable link http://nrs.harvard.edu/urn-3:HUL.InstRepos:25104737 Terms of Use This article was downloaded from Harvard University’s DASH repository, and is made available under the terms and conditions applicable to Other Posted Material, as set forth at http:// nrs.harvard.edu/urn-3:HUL.InstRepos:dash.current.terms-of- use#LAA ¡¢ £¥¤§¦©¨ © ¥ ! " $# %& !'( *)+ %¨,.-/£102©¨ 3¤4#576¥)+ %&8+9©¨ :1)+ 3';&'( )< %' =?>A@CBEDAFHG7DABJILKM GPORQQSOUT3V N W >BYXZ*[CK\@7]_^\`aKbF!^\K/c@C>ZdX eDf@hgiDf@kjmlnF!`ogpKb@CIh`q[UM W DABsr!@k`ajdtKAu!vwDAIhIkDi^Rx_Z!ILK[h[SI ML Module Mania: A Type-Safe, Separately Compiled, Extensible Interpreter Norman Ramsey Division of Engineering and Applied Sciences Harvard University Abstract An application that uses an embedded interpreter is writ- ten in two languages: Most code is written in the original, The new embedded interpreter Lua-ML combines extensi- host language (e.g., C, C++, or ML), but key parts can be bility and separate compilation without compromising type written in the embedded language. This organization has safety. The interpreter’s types are extended by applying a several benefits: sum constructor to built-in types and to extensions, then • Complex command-line arguments aren’t needed; the tying a recursive knot using a two-level type; the sum con- embedded language can be used on the command line.
    [Show full text]
  • No-Longer-Foreign: Teaching an ML Compiler to Speak C “Natively”
    Electronic Notes in Theoretical Computer Science 59 No. 1 (2001) URL: http://www.elsevier.nl/locate/entcs/volume59.html 16 pages No-Longer-Foreign: Teaching an ML compiler to speak C “natively” Matthias Blume 1 Lucent Technologies, Bell Laboratories Abstract We present a new foreign-function interface for SML/NJ. It is based on the idea of data- level interoperability—the ability of ML programs to inspect as well as manipulate C data structures directly. The core component of this work is an encoding of the almost 2 complete C type sys- tem in ML types. The encoding makes extensive use of a “folklore” typing trick, taking advantage of ML’s polymorphism, its type constructors, its abstraction mechanisms, and even functors. A small low-level component which deals with C struct and union declarations as well as program linkage is hidden from the programmer’s eye by a simple program-generator tool that translates C declarations to corresponding ML glue code. 1 An example Suppose you are an ML programmer who wants to link a program with some C rou- tines. The following example (designed to demonstrate data-level interoperability rather than motivate the need for FFIs in the first place) there are two C functions: input reads a list of records from a file and findmin returns the record with the smallest i in a given list. The C library comes with a header file ixdb.h that describes this interface: typedef struct record *list; struct record { int i; double x; list next; }; extern list input (char *); extern list findmin (list); Our ml-nlffigen tool translates ixdb.h into an ML interface that corre- sponds nearly perfectly to the original C interface.
    [Show full text]
  • Tierless Web Programming in ML Gabriel Radanne
    Tierless Web programming in ML Gabriel Radanne To cite this version: Gabriel Radanne. Tierless Web programming in ML. Programming Languages [cs.PL]. Université Paris Diderot (Paris 7), 2017. English. tel-01788885 HAL Id: tel-01788885 https://hal.archives-ouvertes.fr/tel-01788885 Submitted on 9 May 2018 HAL is a multi-disciplinary open access L’archive ouverte pluridisciplinaire HAL, est archive for the deposit and dissemination of sci- destinée au dépôt et à la diffusion de documents entific research documents, whether they are pub- scientifiques de niveau recherche, publiés ou non, lished or not. The documents may come from émanant des établissements d’enseignement et de teaching and research institutions in France or recherche français ou étrangers, des laboratoires abroad, or from public or private research centers. publics ou privés. Distributed under a Creative Commons Attribution - NonCommercial - ShareAlike| 4.0 International License Thèse de doctorat de l’Université Sorbonne Paris Cité Préparée à l’Université Paris Diderot au Laboratoire IRIF Ecole Doctorale 386 — Science Mathématiques De Paris Centre Tierless Web programming in ML par Gabriel Radanne Thèse de Doctorat d’informatique Dirigée par Roberto Di Cosmo et Jérôme Vouillon Thèse soutenue publiquement le 14 Novembre 2017 devant le jury constitué de Manuel Serrano Président du Jury Roberto Di Cosmo Directeur de thèse Jérôme Vouillon Co-Directeur de thèse Koen Claessen Rapporteur Jacques Garrigue Rapporteur Coen De Roover Examinateur Xavier Leroy Examinateur Jeremy Yallop Examinateur This work is licensed under a Creative Commons “Attribution- NonCommercial-ShareAlike 4.0 International” license. Abstract Eliom is a dialect of OCaml for Web programming in which server and client pieces of code can be mixed in the same file using syntactic annotations.
    [Show full text]
  • Seaflow Language Reference Manual Rohan Arora, Junyang Jin, Ho Sanlok Lee, Sarah Seidman Ra3091, Jj3132, Hl3436, Ss5311
    Seaflow Language Reference Manual Rohan Arora, Junyang Jin, Ho Sanlok Lee, Sarah Seidman ra3091, jj3132, hl3436, ss5311 1 Introduction 3 2 Lexical Conventions 3 2.1 Comments 3 2.2 Identifiers 3 2.3 Keywords 3 2.4 Literals 3 3 Expressions and Statements 3 3.1 Expressions 4 3.1.1 Primary Expressions 4 3.1.1 Operators 4 3.1.2 Conditional expression 4 3.4 Statements 5 3.4.1 Declaration 5 3.4.2 Immutability 5 3.4.3 Observable re-assignment 5 4 Functions Junyang 6 4.1 Declaration 6 4.2 Scope rules 6 4.3 Higher Order Functions 6 5 Observables 7 5.1 Declaration 7 5.2 Subscription 7 5.3 Methods 7 6 Conversions 9 1 Introduction Seaflow is an imperative language designed to address the asynchronous event conundrum by supporting some of the core principles of ReactiveX and reactive programming natively. Modern applications handle many asynchronous events, but it is difficult to model such applications using programming languages such as Java and JavaScript. One popular solution among the developers is to use ReactiveX implementations in their respective languages to architect event-driven reactive models. However, since Java and JavaScript are not designed for reactive programming, it leads to complex implementations where multiple programming styles are mixed-used. Our goals include: 1. All data types are immutable, with the exception being observables, no pointers 2. The creation of an observable should be simple 3. Natively support core principles in the ReactiveX specification 2 Lexical Conventions 2.1 Comments We use the characters /* to introduce a comment, which terminates with the characters */.
    [Show full text]
  • JNI – C++ Integration Made Easy
    JNI – C++ integration made easy Evgeniy Gabrilovich Lev Finkelstein [email protected] [email protected] Abstract The Java Native Interface (JNI) [1] provides interoperation between Java code running on a Java Virtual Machine and code written in other programming languages (e.g., C++ or assembly). The JNI is useful when existing libraries need to be integrated into Java code, or when portions of the code are implemented in other languages for improved performance. The Java Native Interface is extremely flexible, allowing Java methods to invoke native methods and vice versa, as well as allowing native functions to manipulate Java objects. However, this flexibility comes at the expense of extra effort for the native language programmer, who has to explicitly specify how to connect to various Java objects (and later to disconnect from them, to avoid resource leak). We suggest a template-based framework that relieves the C++ programmer from most of this burden. In particular, the proposed technique provides automatic selection of the right functions to access Java objects based on their types, automatic release of previously acquired resources when they are no longer necessary, and overall simpler interface through grouping of auxiliary functions. Introduction The Java Native Interface1 is a powerful framework for seamless integration between Java and other programming languages (called “native languages” in the JNI terminology). A common case of using the JNI is when a system architect wants to benefit from both worlds, implementing communication protocols in Java and computationally expensive algorithmic parts in C++ (the latter are usually compiled into a dynamic library, which is then invoked from the Java code).
    [Show full text]
  • Difference Between Method Declaration and Signature
    Difference Between Method Declaration And Signature Asiatic and relaxed Dillon still terms his tacheometry namely. Is Tom dirt or hierarchal after Zyrian Nelson hasting so variously? Heterozygous Henrique instals terribly. Chapter 15 Functions. How junior you identify a function? There play an important difference between schedule two forms of code block seeing the. Subroutines in C and Java are always expressed as functions methods which may. Only one params keyword is permitted in a method declaration. Complex constant and so, where you declare checked exception parameters which case, it prompts the method declaration group the habit of control passes the positional. Overview of methods method parameters and method return values. A whole object has the cash public attributes and methods. Defining Methods. A constant only be unanimous a type explicitly by doing constant declaration or. As a stop rule using prototypes is the preferred method as it. C endif Class HelloJNI Method sayHello Signature V JNIEXPORT. Method signature It consists of the method name just a parameter list window of. As I breathe in the difference between static and dynamic binding static methods are. Most electronic signature solutions in the United States fall from this broad. DEPRECATED Method declarations with type constraints and per source filter. Methods and Method Declaration in Java dummies. Class Methods Apex Developer Guide Salesforce Developers. Using function signatures to remove a library method Function signatures are known important snapshot of searching for library functions The F libraries. Many different kinds of parameters with rather subtle semantic differences. For addition as real numbers the distinction is somewhat moot because is.
    [Show full text]
  • Data Types Are Values
    Data Types Are Values James Donahue Alan Demers Data Types Are Values James Donahue Xerox Corporation Palo Alto Research Center 3333 Coyote Hill Road Palo Alto, California 94304 Alan Demers Computer Science Department Cornell University Ithaca, New York 14853 CSL -83-5 March 1984 [P83-00005] © Copyright 1984 ACM. All rights reserved. Reprinted with permission. A bst ract: An important goal of programming language research is to isolate the fundamental concepts of languages, those basic ideas that allow us to understand the relationship among various language features. This paper examines one of these underlying notions, data type, with particular attention to the treatment of generic or polymorphic procedures and static type-checking. A version of this paper will appear in the ACM Transact~ons on Programming Languages and Systems. CR Categories and Subject Descriptors: 0.3 (Programming Languages), 0.3.1 (Formal Definitions and Theory), 0.3.3 (Language Constructs), F.3.2 (Semantics of Programming Languages) Additional Keywords and Phrases: data types, polymorphism XEROX Xerox Corporation Palo Alto Research Center 3333 Coyote Hill Road Palo Alto, California 94304 DATA TYPES ARE VALVES 1 1. Introduction An important goal of programming language research is to isolate the fundamental concepts of languages, those basic ideas that allow us to understand the relationship among various language features. This paper examines one of these underlying notions, data type, and presents a meaning for this term that allows us to: describe a simple treatment of generic or polymorphic procedures that preserves full static type-checking and allows unrestricted use of recursion; and give a precise meaning to the phrase strong typing, so that Language X is strongly typed can be interpreted as a critically important theorem about the semantics of the language.
    [Show full text]
  • Exploring Languages with Interpreters and Functional Programming Chapter 22
    Exploring Languages with Interpreters and Functional Programming Chapter 22 H. Conrad Cunningham 5 November 2018 Contents 22 Overloading and Type Classes 2 22.1 Chapter Introduction . .2 22.2 Polymorphism in Haskell . .2 22.3 Why Overloading? . .2 22.4 Defining an Equality Class and Its Instances . .4 22.5 Type Class Laws . .5 22.6 Another Example Class Visible ..................5 22.7 Class Extension (Inheritance) . .6 22.8 Multiple Constraints . .7 22.9 Built-In Haskell Classes . .8 22.10Comparison to Other Languages . .8 22.11What Next? . .9 22.12Exercises . 10 22.13Acknowledgements . 10 22.14References . 11 22.15Terms and Concepts . 11 Copyright (C) 2017, 2018, H. Conrad Cunningham Professor of Computer and Information Science University of Mississippi 211 Weir Hall P.O. Box 1848 University, MS 38677 (662) 915-5358 Browser Advisory: The HTML version of this textbook requires use of a browser that supports the display of MathML. A good choice as of November 2018 is a recent version of Firefox from Mozilla. 1 22 Overloading and Type Classes 22.1 Chapter Introduction Chapter 5 introduced the concept of overloading. Chapters 13 and 21 introduced the related concepts of type classes and instances. The goal of this chapter and the next chapter is to explore these concepts in more detail. The concept of type class was introduced into Haskell to handle the problem of comparisons, but it has had a broader and more profound impact upon the development of the language than its original purpose. This Haskell feature has also had a significant impact upon the design of subsequent languages (e.g.
    [Show full text]
  • What I Wish I Knew When Learning Haskell
    What I Wish I Knew When Learning Haskell Stephen Diehl 2 Version This is the fifth major draft of this document since 2009. All versions of this text are freely available onmywebsite: 1. HTML Version ­ http://dev.stephendiehl.com/hask/index.html 2. PDF Version ­ http://dev.stephendiehl.com/hask/tutorial.pdf 3. EPUB Version ­ http://dev.stephendiehl.com/hask/tutorial.epub 4. Kindle Version ­ http://dev.stephendiehl.com/hask/tutorial.mobi Pull requests are always accepted for fixes and additional content. The only way this document will stayupto date and accurate through the kindness of readers like you and community patches and pull requests on Github. https://github.com/sdiehl/wiwinwlh Publish Date: March 3, 2020 Git Commit: 77482103ff953a8f189a050c4271919846a56612 Author This text is authored by Stephen Diehl. 1. Web: www.stephendiehl.com 2. Twitter: https://twitter.com/smdiehl 3. Github: https://github.com/sdiehl Special thanks to Erik Aker for copyediting assistance. Copyright © 2009­2020 Stephen Diehl This code included in the text is dedicated to the public domain. You can copy, modify, distribute and perform thecode, even for commercial purposes, all without asking permission. You may distribute this text in its full form freely, but may not reauthor or sublicense this work. Any reproductions of major portions of the text must include attribution. The software is provided ”as is”, without warranty of any kind, express or implied, including But not limitedtothe warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authorsor copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, Arising from, out of or in connection with the software or the use or other dealings in the software.
    [Show full text]
  • Idris: a Functional Programming Language with Dependent Types
    Programming Languages and Compiler Construction Department of Computer Science Christian-Albrechts-University of Kiel Seminar Paper Idris: A Functional Programming Language with Dependent Types Author: B.Sc. Finn Teegen Date: 20th February 2015 Advised by: M.Sc. Sandra Dylus Contents 1 Introduction1 2 Fundamentals2 2.1 Universes....................................2 2.2 Type Families..................................2 2.3 Dependent Types................................3 2.4 Curry-Howard Correspondence........................4 3 Language Overview5 3.1 Simple Types and Functions..........................5 3.2 Dependent Types and Functions.......................6 3.3 Implicit Arguments...............................7 3.4 Views......................................8 3.5 Lazy Evaluation................................8 3.6 Syntax Extensions...............................9 4 Theorem Proving 10 4.1 Propositions as Types and Terms as Proofs................. 10 4.2 Encoding Intuitionistic First-Order Logic................... 12 4.3 Totality Checking................................ 14 5 Conclusion 15 ii 1 Introduction In conventional Hindley-Milner based programming languages, such as Haskell1, there is typically a clear separation between values and types. In dependently typed languages, however, this distinction is less clear or rather non-existent. In fact, types can depend on arbitrary values. Thus, they become first-class citizens and are computable like any other value. With types being allowed to contain values, they gain the possibility to describe prop- erties of their own elements. The standard example for dependent types is the type of lists of a given length - commonly referred to as vectors - where the length is part of the type itself. When starting to encode properties of values as types, the elements of such types can be seen as proofs that the stated property is true.
    [Show full text]
  • System F and Existential Types 15-312: Foundations of Programming Languages
    Recitation 6: System F and Existential Types 15-312: Foundations of Programming Languages Serena Wang, Charles Yuan February 21, 2018 We saw how to use inductive and coinductive types last recitation. We can also add polymorphic types to our type system, which leads us to System F. With polymorphic types, we can have functions that work the same regardless of the types of some parts of the expression.1 1 System F Inductive and coinductive types expand the expressivity of T considerably. The power of type operators allows us to genericly manipulate data of heterogeneous types, building new types from old ones. But to write truly \generic" programs, we want truly polymorphic expressions| functions that operate on containers of some arbitrary type, for example. To gain this power, we add parametric polymorphism to the language, which results in System F, introduced by Girand (1972) and Reynolds (1974). Typ τ ::= t type variable τ1 ! τ2 function 8(t.τ) universal type Exp e ::= x variable λ (x : τ) e abstraction e1(e2) application Λ(t) e type abstraction e[τ] type application Take stock of what we've added since last time, and what we've removed. The familiar type variables are now baked into the language, along with the universal type. We also have a new form of lambda expression, one that works over type variables rather than expression variables. What's missing? Nearly every other construct we've come to know and love! As will be the case repeatedly in the course, our tools such as products, sums, and inductive types are subsumed by the new polymorphic types.
    [Show full text]
  • Constrained Type Families (Extended Version)
    Constrained Type Families (extended version) J. GARRETT MORRIS, e University of Edinburgh and e University of Kansas 42 RICHARD A. EISENBERG, Bryn Mawr College We present an approach to support partiality in type-level computation without compromising expressiveness or type safety. Existing frameworks for type-level computation either require totality or implicitly assume it. For example, type families in Haskell provide a powerful, modular means of dening type-level computation. However, their current design implicitly assumes that type families are total, introducing nonsensical types and signicantly complicating the metatheory of type families and their extensions. We propose an alternative design, using qualied types to pair type-level computations with predicates that capture their domains. Our approach naturally captures the intuitive partiality of type families, simplifying their metatheory. As evidence, we present the rst complete proof of consistency for a language with closed type families. CCS Concepts: •eory of computation ! Type structures; •So ware and its engineering ! Func- tional languages; Additional Key Words and Phrases: Type families, Type-level computation, Type classes, Haskell ACM Reference format: J. Garre Morris and Richard A. Eisenberg. 2017. Constrained Type Families (extended version). PACM Progr. Lang. 1, 1, Article 42 (January 2017), 38 pages. DOI: hp://dx.doi.org/10.1145/3110286 1 INTRODUCTION Indexed type families (Chakravarty et al. 2005; Schrijvers et al. 2008) extend the Haskell type system with modular type-level computation. ey allow programmers to dene and use open mappings from types to types. ese have given rise to further extensions of the language, such as closed type families (Eisenberg et al.
    [Show full text]