ArticlePDF Available

How to Make Ad-Hoc Polymorphism Less Ad Hoc

Authors:

Abstract

This paper presents type classes, a new approach to ad-hoc polymorphism. Type classes permit overloading of arithmetic operators such as multiplication, and generalise the "eqtype variables" of Standard ML. Type classes extend the Hindley/Milner polymorphic type system, and provide a new approach to issues that arise in object-oriented programming, bounded type quantification, and abstract data types. This paper provides an informal introduction to type classes, and defines them formally by means of type inference rules. 1 Introduction Strachey chose the adjectives ad-hoc and parametric to distinguish two varieties of polymorphism [Str67]. Ad-hoc polymorphism occurs when a function is defined over several different types, acting in a different way for each type. A typical example is overloaded multiplication: the same symbol may be used to denote multiplication of integers (as in 3*3) and multiplication of floating point values (as in 3.14*3.14). Parametric polymorphism occurs wh...
... Traditionally, for languages with type-directed semantics, elaboration has been a common choice. That is the case, for instance, for many previous calculi with the merge operator (Dunfield, 2014;Oliveira et al., 2016;Alpuim et al., 2017;Bi et al., , 2019, gradual typing (Siek & Taha, 2006), or type classes (Wadler & Blott, 1989;Kaes, 1988). In the elaboration approach, the idea is that the source language can be translated via a type-directed translation into a conventional target calculus, whose semantics is not type directed. ...
... Type classes. (Wadler & Blott, 1989;Kaes, 1988) are an approach to parametric overloading used in languages like Haskell. The commonly adopted compilation strategy for it is the dictionary passing style elaboration (Wadler & Blott, 1989;Hall et al., 1996;Chakravarty et al., 2005a,b). ...
... (Wadler & Blott, 1989;Kaes, 1988) are an approach to parametric overloading used in languages like Haskell. The commonly adopted compilation strategy for it is the dictionary passing style elaboration (Wadler & Blott, 1989;Hall et al., 1996;Chakravarty et al., 2005a,b). Other mechanisms inspired by type classes, such as Scala's implicits (Oliveira et al., 2010), Agda's instance arguments (Devriese & Piessens, 2011) or Ocaml's modular implicits (White et al., 2014) have an elaboration semantics as well. ...
Article
Calculi with disjoint intersection types support a symmetric merge operator with subtyping. The merge operator generalizes record concatenation to any type, enabling expressive forms of object composition, and simple solutions to hard modularity problems. Unfortunately, recent calculi with disjoint intersection types and the merge operator lack a (direct) operational semantics with expected properties such as determinism and subject reduction , and only account for terminating programs . This paper proposes a type-directed operational semantics (TDOS) for calculi with intersection types and a merge operator. We study two variants of calculi in the literature. The first calculus, called λ i , is a variant of a calculus presented by Oliveira et al. (2016) and closely related to another calculus by Dunfield (2014). Although Dunfield proposes a direct small-step semantics for her calculus, her semantics lacks both determinism and subject reduction. Using our TDOS, we obtain a direct semantics for λ i that has both properties. The second calculus, called λ i + , employs the well-known subtyping relation of Barendregt, Coppo and Dezani-Ciancaglini (BCD). Therefore, λ i + extends the more basic subtyping relation of λ i , and also adds support for record types and nested composition (which enables recursive composition of merged components). To fully obtain determinism, both λ i and λ i + employ a disjointness restriction proposed in the original λ i calculus. As an added benefit the TDOS approach deals with recursion in a straightforward way, unlike previous calculi with disjoint intersection types where recursion is problematic. We relate the static and dynamic semantics of λ i to the original version of the calculus and the calculus by Dunfield. Furthermore, for λ i + , we show a novel formulation of BCD subtyping, which is algorithmic, has a very simple proof of transitivity and allows for the modular addition of distributivity rules (i.e. without affecting other rules of subtyping). All results have been fully formalized in the Coq theorem prover.
... The elaboration semantics for F + i seems like a natural choice, since this is commonly seen in various other type-dependent languages and calculi. For instance, the semantics of type-dependent languages with type classes [43], Scala-style implicits [29] or gradual typing [40] all usually adopt an elaboration approach. In contrast, in the past, more conventional direct formulations using an operational semantics have been avoided for languages with a type-dependent semantics. ...
... The appeals of the elaboration semantics are simple type-safety proofs, and the fact that they directly offer an implementation technique over conventional languages without a type-dependent semantics. For instance, the semantics of type-dependent languages with type classes [18,43], Scala-style implicits [27,29] or gradual typing [40] all use an elaboration semantics. In contrast, in the past, more conventional direct formulations using an operational semantics have been avoided for languages with a type-dependent semantics. ...
Preprint
Full-text available
The recently proposed CP language adopts Compositional Programming: a new modular programming style that solves challenging problems such as the Expression Problem. CP is implemented on top of a polymorphic core language with disjoint intersection types called Fi+. The semantics of Fi+ employs an elaboration to a target language and relies on a sophisticated proof technique to prove the coherence of the elaboration. Unfortunately, the proof technique is technically challenging and hard to scale to many common features, including recursion or impredicative polymorphism. Thus, the original formulation of Fi+ does not support the two later features, which creates a gap between theory and practice, since CP fundamentally relies on them. This paper presents a new formulation of Fi+ based on a type-directed operational semantics (TDOS). The TDOS approach was recently proposed to model the semantics of languages with disjoint intersection types (but without polymorphism). Our work shows that the TDOS approach can be extended to languages with disjoint polymorphism and model the full Fi+ calculus. Unlike the elaboration semantics, which gives the semantics to Fi+ indirectly via a target language, the TDOS approach gives a semantics to Fi+ directly. With a TDOS, there is no need for a coherence proof. Instead, we can simply prove that the semantics is deterministic. The proof of determinism only uses simple reasoning techniques, such as straightforward induction, and is able to handle problematic features such as recursion and impredicative polymorphism. This removes the gap between theory and practice and validates the original proofs of correctness for CP. We formalized the TDOS variant of the Fi+ calculus and all its proofs in the Coq proof assistant.
... Many design patterns have been proposed to enable the theory of a general structure (such as monoids) to be applied seamlessly to more specific structures (such as fields), including canonical structures in Coq [11], locales in Isabelle [15], unification hints in Matita [2] and attributed types in Mizar [12]. The Lean mathematical library mathlib [23] has settled on the use of the typeclass [25] pattern for representing structures, implemented through Lean's mechanism of instance parameters [7,8]. Typeclasses were invented by Wadler to provide ad hoc polymorphism in Haskell [25]. ...
... The Lean mathematical library mathlib [23] has settled on the use of the typeclass [25] pattern for representing structures, implemented through Lean's mechanism of instance parameters [7,8]. Typeclasses were invented by Wadler to provide ad hoc polymorphism in Haskell [25]. Similar mechanisms can now be found in programming languages including Idris [3], Rust [17,Chapter 6.11] and Scala [16], and interactive theorem provers including Agda [10], Coq [21] and Isabelle [26]. ...
Preprint
Full-text available
The Lean mathematical library mathlib features extensive use of the typeclass pattern for organising mathematical structures, based on Lean's mechanism of instance parameters. Related mechanisms for typeclasses are available in other provers including Agda, Coq and Isabelle with varying degrees of adoption. This paper analyses representative examples of design patterns involving instance parameters in the current Lean 3 version of mathlib, focussing on complications arising at scale and how the mathlib community deals with them.
... A delicate practical issue of the transformation is the typing of the transformed programs. Curry is a strongly typed language with parametric types and type classes (Wadler and Blott 1989). Since logic programs and standard Prolog do not contain type information, our tool defines a single type Term containing all atoms and functors occurring in the logic program. ...
Preprint
Logic programming is a flexible programming paradigm due to the use of predicates without a fixed data flow. To extend logic languages with the compact notation of functional programming, there are various proposals to map evaluable functions into predicates in order to stay in the logic programming framework. Since amalgamated functional logic languages offer flexible as well as efficient evaluation strategies, we propose an opposite approach in this paper. By mapping logic programs into functional logic programs with a transformation based on inferring functional dependencies, we develop a fully automatic transformation which keeps the flexibility of logic programming but can improve computations by reducing infinite search spaces to finite ones.
... We will return to this when we discuss algebraic language in Section 7. Computational implementations of mathematical language use various mechanisms to infer the relevant structure. Even ad-hoc uses of an addition symbol can be used as instances of an "addition structure" [Wadler and Blott, 1989]. ...
Article
As idealized descriptions of mathematical language, there is a sense in which formal systems specify too little, and there is a sense in which they specify too much. They are silent with respect to a number of features of mathematical language that are essential to the communicative and inferential goals of the subject, while many of these features are independent of a specific choice of foundation. This chapter begins to map out the design features of mathematical language without descending to the level of formal implementation, drawing on examples from the mathematical literature and insights from the design of computational proof assistants.
... Typeclass Resolution. Typeclasses [16] provide an elegant and effective way of managing ad-hoc polymorphism in both programming languages and interactive proof assistants. Then we can declare particular elements of a typeclass to be instances. ...
Chapter
Full-text available
Lean 4 is a reimplementation of the Lean interactive theorem prover (ITP) in Lean itself. It addresses many shortcomings of the previous versions and contains many new features. Lean 4 is fully extensible: users can modify and extend the parser, elaborator, tactics, decision procedures, pretty printer, and code generator. The new system has a hygienic macro system custom-built for ITPs. It contains a new typeclass resolution procedure based on tabled resolution, addressing significant performance problems reported by the growing user base. Lean 4 is also an efficient functional programming language based on a novel programming paradigm called functional but in-place . Efficient code generation is crucial for Lean users because many write custom proof automation procedures in Lean itself.
Article
Multi-stage programming using typed code quotation is an established technique for writing optimizing code generators with strong type-safety guarantees. Unfortunately, quotation in Haskell interacts poorly with type classes, making it difficult to write robust multi-stage programs. We study this unsound interaction and propose a resolution, staged type class constraints, which we formalize in a source calculus λ ⇒ that elaborates into an explicit core calculus F . We show type soundness of both calculi, establishing that well-typed, well-staged source programs always elaborate to well-typed, well-staged core programs, and prove beta and eta rules for code quotations. Our design allows programmers to incorporate type classes into multi-stage programs with confidence. Although motivated by Haskell, it is also suitable as a foundation for other languages that support both overloading and quotation.
Chapter
The Go programming language is an increasingly popular language but some of its features lack a formal investigation. This article explains Go’s resolution mechanism for overloaded methods and its support for structural subtyping by means of translation from Featherweight Go to a simple target language. The translation employs a form of dictionary passing known from type classes in Haskell and preserves the dynamic behavior of Featherweight Go programs.
Article
Full-text available
Luis Damas No contact information provided yet. Bibliometrics: publication history Publication years1982-2008 Publication count20 Citation Count259 Available for download5 Downloads (6 Weeks)30 Downloads (12 Months)294 View colleagues of Luis Damas Robin Milner Homepage Bibliometrics: publication history Publication years1971-2009 Publication count93 Citation Count5,537 Available for download13 Downloads (6 Weeks)97 Downloads (12 Months)847 View colleagues of Robin Milner
Article
The aim of this work is largely a practical one. A widely employed style of programming, particularly in structure-processing languages which impose no discipline of types, entails defining procedures which work well on objects of a wide variety. We present a formal type discipline for such polymorphic procedures in the context of a simple programming language, and a compile time type-checking algorithm which enforces the discipline. A Semantic Soundness Theorem (based on a formal semantics for the language) states that well-type programs cannot “go wrong” and a Syntactic Soundness Theorem states that if accepts a program then it is well typed. We also discuss extending these results to richer languages; a type-checking algorithm based on is in fact already implemented and working, for the metalanguage ML in the Edinburgh LCF system.
Conference Paper
The problem of strong typing is considered for a model of object-oriented programming systems. These systems permit values which are records of other values, and in which fields inside these records are retrieved by name. A type system is proposed that permits classification of these kinds of values and programs by the type of their result, as is usual in strongly-typed programming languages. The type system has two important properties: it admits multiple inheritance, and it has a syntactically complete type inference system.
Conference Paper
We show how a programming language designer may embed the type structure of a programming language in the more robust type structure of the typed lambda calculus. This is done by translating programs of the language into terms of the typed lambda calculus. ...
Article
Abstract data type declarations appear in typed programming languages like Ada, Alphard, CLU and ML. This form of declaration binds a list of identifiers to a type with associated operations, a composite “value” we call a data algebra. We use a second-order typed lambda calculus SOL to show how data algebras may be given types, passed as parameters, and returned as results of function calls. In the process, we discuss the semantics of abstract data type declarations and review a connection between typed programming languages and constructive logic.