Type classes an exploration of the design space

Simon Peyton Jones Mark Jones

University of Glasgow and Oregon Graduate Institute University of Nottingham

Erik Meijer

University of Utrecht and Oregon Graduate Institute

May

Abstract to Haskell can b e a painful exp erience One feature that is

particularly often missed is multiparameter type classes

Section explains why

When type classes were rst introduced in Haskell they

were regarded as a fairly exp erimental language feature and

The obvious question is whether there is an upward

therefore warranted a fairly conservative design Since that

compatible way to extend Haskells class system to enjoy

time practical exp erience has convinced many programmers

some or all of the expressiveness that Gofer provides and

of the b enets and convenience of type classes However on

p erhaps some more b esides The main b o dy of this pap er

o ccasion these same programmers have discovered examples

explores this question in detail It turns out that there are

where seemingly natural applicatio ns for overload

a number of interlocking design decisions to b e made Gofer

ing are prevented by the restrictions imp osed by the Haskell

and Haskell each embo dy a particular set but it is very

design

useful to tease them out indep endently and see how they

interact Our goal is to explore the design space as clearly

It is p ossible to extend the type class mechanism of Haskell

as p ossible laying out the choices that must b e made and

in various ways to overcome these limitations but such pro

the factors that aect them rather than prescribing a par

p osals must b e designed with great care For example sev

ticular solution Section We nd that the design space

eral dierent extensions have b een implemented in Gofer

is rather large we identify nine separate design decisions

Some of these particularly the supp ort for multiparameter

each of which has two or more p ossible choices though not

classes have proved to b e very useful but interactions b e

all combinations of choices make sense In the end however

tween other asp ects of the design have resulted in a type

we do oer our own opinion ab out a sensible set of choices

system that is b oth unsound and undecidable Another illus

Section

tration is the introduction of constructor classes in Haskell

which came without the prop er generalizatio n of the no

A new language feature is only justiable if it results in a

tion of a context As a consequence certain quite reasonable

simplicati on or unication of the original language design

programs are not typable

or if the extra expressiveness is truly useful in practice One

contribution of this pap er is to collect together a fairly large

In this pap er we review the rationale b ehind the design of

set of examples that motivate various extensions to Haskells

Haskells class system we identify some of the weaknesses

type classes

in the current situation and we explain the choices that we

face in attempting to remove them

Why multiparameter type classes

Introduction

The most visible extension to Haskell type classes that we

discuss is supp ort for multiparameter type classes The p os

Type classes are one of the most distinctive features of

sibility of multiparameter type classes has b een recognised

Haskell Hudak et al They have b een used for an

since the original pap ers on the sub ject Kaes Wadler

1

impressive variety of application s and Haskell signif

Blott and Gofer has always supp orted them

icantly extended their expressiveness by introducing con

structor classes Jones a

This section collects together examples of multiparameter

type classes that we have encountered None of them are

All programmers want more than they are given and many

new none will b e surprising to the cognescenti and many

p eople have bump ed up against the limitation s of Haskells

have app eared inter alia in other pap ers Our purp ose in

class system Another language Gofer Jones that

collecting them is to provide a shared database of motivating

has developed in parallel with Haskell enjoys a much more

examples We would welcome new contributions

lib eral and expressive class system This expressiveness is

denitely b oth useful and used and transferring from Gofer

1

The current iteration of the Haskell language is Haskell but it is identical to Haskell in all resp ects relevant to this pap er

Overloading with coupled parameters

newtype Env e a Env e a

instance ReaderMonad Env e e where

Concurrent Haskell Peyton Jones Gordon Finne

introduces a number of types such as mutable variables

Work in Glasgow and the Oregon Graduate Institute

MutVar synchronised mutable variables MVar channel

on hardware description languages has led to class dec

variables CVar communication channels Channel and skip

larations similar to this

channels SkipChan all of which come with similar op era

tions that take the form

class Monad ct Hard ct sg where

newX a IO X a

const a ct sg a

getX X a IO a

op a b sg a ct sg b

putX X a a IO

op a b c sg a sg b ct s c

where X ranges over MVar etc Here are similar op erations

instance Hard NetCircuit NetSignal where

in the standard state monad

instance Hard SimCircuit SimSignal where

newST a ST s MutableVar s a

Here the circuit constructor ct is a monad while

getST MutableVar s a ST s a

the signal constructor sg serves to distinguish values

putST MutableVar s a a ST s

available at circuitconstruction time of type Int say

These are manifestly candidates for overloading yet a single

from those owing along the wires at circuitexecution

parameter type class cant do the trick The trouble is that

time of type SimSignal Int say Each instance of

in each case the monad type and the reference type come as

Hard gives a dierent interpretation of the circuit for

a pair IO MutVar and ST s MutableVar s What we

example one might pro duce a net list while another

want is a multiple parameter class that abstracts over b oth

might simulate the circuit

Like the VarMonad example the instance type come as

class Monad m VarMonad m v where

a pair it would make no sense to give an instance for

new a m v a

Hard NetCircuit SimSignal

get v a m a

put v a a m

2

The Haskell prelude denes denes the following two

functions for reading and writing les

instance VarMonad IO MutVar where

instance VarMonad ST s MutableVar s where

readFile FilePath IO String

writeFile FilePath String IO

This is quite a common pattern in which a twoparameter

type class is needed b ecause the class signature is really over

Similar functions can b e dened for many more pairs

a tuple of types and where instance declarations capture di

of device handles and communicatable types such as

rect relationshi ps b etween sp ecic tuples of type construc

mice buttons timers windows rob ots etc

tors We call this overloading with coupled parameters

Here are a number of other examples we have collected

readMouse Mouse IO MouseEvent

readButton Button IO

readTimer Timer IO Float

The class StateMonad Jones carries the state

around naked instead of inside a container as in the

sendWindow Window Picture IO

VarMonad example

sendRobot Robot Command IO

sendTimer Timer Float IO

class Monad m StateMonad m s where

getS m s

These functions are quite similar to the metho ds

putS s m

get VarMonad r m r a m a and put

VarMonad r m r a a m of the VarMonad

Here the monad m carries along a state of type s getS

family except that here the monad m is xed to IO and

extracts the state from the monad and putS overwrites

the choice of the value type a is coupled with the b ox

the state with a new value One can then dene in

type v a So what we need here is a multiparameter

stances of StateMonad

class that overloads on v a and a instead

newtype State s a State s as

class IODevice handle a where

instance StateMonad State s s where

receive handle IO a

send handle a IO a

Notice the coupling b etween the parameters arising

from the rep eated type variable s Jones also

Perhaps one could go one step further and unify class

denes a related class ReaderMonad that describ es

IODevice r a and class Monad m StateMonad m

computations that read some xed environment

r into a three parameter class class Monad m

Device m r a

class Monad m ReaderMonad m e where

env e m a m a

2

This example was suggested by Enno Scholz

getenv m e

3

An app ealing application of type classes is to de serves as a ho ok either for one of the other arguments or

scrib e mathematical structures such as groups elds for the instance context and member functions to use

monoids and so on But it is not long b efore the need

The parametric type classes of Chen Hudak Odersky

for coupled overloading arises For example

also deal quite nicely with the bulktypes example

but their assymetry do es not suit the examples of the pre

class Field k AdditiveGroup a

vious section so well A full discussion of the design choices

VectorSpace k a where

for a bulktypes library is contained in Peyton Jones

k a a

Type relations

Here the op erator multiplies a vector by a scalar

One can also construct applications for multiparameter

classes where the relationshi ps b etween dierent parame

Overloading with constrained parame

ters are much lo oser than in the examples that we have

ters

seen ab ove After all in the most general setting a multi

parameter type class C could b e used to represent an arbi

Libraries that implement sets bags lists nite maps and so

trary relation b etween types where for example a b is in

on all use similar functions empty insert union lookup

the relation if and only if there is an instance for C a b

etc There is no commonlyagreed signature for such li

braries that usefully exploits the class system One reason

One can imagine dening an isomorphism relationship

for this is that multiparameter type classes are absolutely

b etween types Liang Hudak Jones

required to do a go o d job Why Consider this rst attempt

class Collection c where class Iso a b where

empty c a iso a b

insert a c a c a osi b a

union c a c a c a

etc instance Iso a a where iso id

The trouble is that the type variable a is universal ly quan

One could imagine overloading Haskells eld selectors

tied in the signature for insert union and so on This

by declaring a class

means we cannot use equality or greaterthan on the ele

ments so we cannot make sets an instance of Collection

class Hasf a b where

which rather defeats the ob ject of the exercise By far the

f a b

b est solution is to use a twoparameter type class thus

for any eld lab el f So if we have the

class Collection c a where

Foo Foofoo Int we would get a class decla

empty c a

ration class Hasfoo a b where foo a b and

insert a c a c a

an instance declaration

union c a c a c a

etc

instance Hasfoo Foo Int where

The use of a multiparameter class allows us to make in

foo Foo foo foo

stance declarations that constrain the element type on a

perinstance basis

This is just a cutdown version of the kind of extensible

records that were prop osed by Jones Jones

instance Eq a Collection ListSet a where

empty

insert a xs

These examples are lo oser than the earlier ones b ecause

etc

the result types of the class op erations do not mention all the

class type variables In practice we typically nd that such

instance Ord a Collection TreeSet a where

relations are to o general for the type class mechanisms and

empty

insert x t

that it b ecomes remarkably easy to write programs whose

etc

overloading is ambiguous

The p oint is that dierent instance declarations can con

For example what is the type of iso a iso b The

strain the element type a in dierent ways One can lo ok

iso function is used at type Char b and the resulting

at this as a variant of coupledparameter overloading dis

values of iso a and iso b are compared with used

cussed in the preceding section Here the second type

at type b b Bool However this intermediate type

in the pair is constrained by the instance declaration eg

is completely unconstrained and hence the resulting type

Ord a rather than completely specied as in the

Eq b Iso Char b Bool is ambiguous One runs into

previous section In general in this form of overloading one

similar problems quickly when trying to use overloading of

or more of the parameters in any instance is a variable that

eld selectors We discuss ambiguity further in Section

3

This example was suggested by Sergey Mechveliani

Summary

TV P dom

In our view the examples of this section make a very p er

instance C P where

inst

suasive case for multiparameter type classes just as Monad

C P

and Functor did for constructor classes These examples

cry out for Haskellstyle overloading but it simply cannot

b e done without multiparameter classes

TV P dom

class C P where

sup er

P C

Background

Q P

mono

In order to describ e the design choices related to type classes

P Q

we must briey review some of the concepts involved

P Q Q R

trans

P R

Inferred contexts

Figure Rules for entailment

When p erforming type inference on an expression the type

checker will infer a a monotype and b a context or set

of constraints that must b e satised For example consider

This instance declaration sp ecies how we can use an

the expression

equality on values of type a to dene an equality on

xs case xs of

lists of type a In terms of the dictionary mo del the

False

instance declaration sp ecies how to construct a dic

yys y z yz ysz

tionary for Eq a from a dictionary for Eq a Hence

we can p erform the following context reduction

Here the type checker will infer that the expression has the

following context and type

fOrd a Eq a Eq ag fOrd a Eq ag

Context fOrd a Eq a Eq ag

Type a Bool

We say that a constraint matches an instance declara

The constraint Ord a arises from the use of on an element

tion if there is a substitution of the type variables in

of the list y the constraint says that the elements of the list

the instance declaration head that makes it equal to

must lie in class Ord Similarly Eq a arises from the use of

the constraint

on a list element The constraint Eq a arises from the

Using a class declaration For example the class dec

use of on the tail of the list it says that lists of elements

laration for Ord in the Haskell Prelude sp ecies that

of type a must also lie in Eq

Eq is a sup erclass of Ord

These typing constraints have an op erational interpretation

that is often helpful though it is not required that a Haskell

class Eq a Ord a where

implementation use this particular op erational mo del For

each constraint there is a corresp onding dictionary a col

What this means is that every instance of Ord is also

lection of functions that will b e passed to the overloaded op

an instance of Eq In terms of the dictionary mo del

erator involved In our example the dictionary for Eq a

we can read this as saying that each Ord dictionary

will b e a tuple of metho ds corresp onding to the class Eq It

contains an Eq dictionary as a subcomp onent So the

will b e passed to the second overloaded op erator which

constraint Eq a is implied by Ord a and it follows that

will simply select the metho d from the dictionary and

we can p erform the following context reduction

apply it to ys and z You can think of a dictionary as

concrete runtime evidence that the constraint is satis

fOrd a Eq ag fOrd ag

ed

More precisely we say that Q entails P written Q P if

the constraints in P are implied by those in Q We dene

Context reduction

the meaning of class constraints more formally using the def

inition of the entailment relation dened in Figure The

4

Contexts can b e simplied or reduced in three main ways

rst two rules corresp ond to and ab ove The sub

stitution maps type variables to types it allows class and

instance declarations to b e used at substitutioni nstan ces of

Eliminating duplicate constraints For example we can

their types For example from the declaration

reduce the context fEq Eq g to just fEq g

instance Eq a Eq a where

Using an instance declaration For example the

4

Haskell Prelude contains the standard instance dec

Notice that in inst C and P app ear in the same order on

laration

the top and b ottom lines of the rules whereas they are reversed in

super This suggest an infelicity in Haskells syntax but one that

it is p erhaps to o late to correct

instance Eq a Eq a where

instance Eq a Foo ab where we can deduce that fEq g fEq g for an arbitrary

5

type The remaining rules explain that entailment is

and let us assume for the moment that overlapping instance

monotonic and transitive as one would exp ect

declarations are prohibited Section Now supp ose that

the context fFoo Inttg is sub ject to context reduction The connection b etween entailment and context reduction

0

Regardless of the type t it can b e simplied to fEq Intg is this to reduce the context P to P it is necessary but

0

using the instance declaration ab ove and thence to fg p erhaps not sucient that P P The reason that en

using the Int instance for Eq Even if t contains type tailment is not sucient for reduction concerns overlapping

0

variables the constraint Foo Intt can still b e reduced instances there might b e more than one P with the prop

0

to fg so it is a tautological constraint erty that P P so which should b e chosen Overlapping

instance declarations are discussed in Section and

Another example of one of these tautological constraints

that contain type variables is given by this instance dec

laration

Failure

instance Monad ST s where

Context reduction fails and a type error is rep orted if there

This declares the state transformer type ST s to b e a

is no instance declaration that can match the given con

monad regardless of the type s

straint For example supp ose that we are trying to reduce

the constraint Eq Tree and there is no instance decla

If on the other hand overlapping instance declarations are

ration of the form

p ermitted then reducing a tautological constraint in this

way is not legitimate as we discuss in Section

instance Eq Tree where

Then we can immediately rep ort an error even if contains

type variables that will later b e further instantiated b ecause

Generalisation

no further renement of can p ossibly make it match This

strategy conicts slightly with separate compilation b ecause

Supp ose that the example in Section is embedded in a

one could imagine that a separatelycompil ed library might

larger expression

not b e able to see all the instance declarations for Tree

let

Arguably therefore rather than rep orting an error message

f xs case xs of

context reduction should b e deferred see Section in the

False

hop e that an imp orting mo dule will have the necessary in

yys y z

stance declaration However that would p ostp one the pro

yz ysz

duction of even legitimate missinginsta nce error messages

in

until the main mo dule is compiled when no further in

stance declarations can o ccur which is quite a serious dis

advantage Furthermore it is usually easy to arrange that

Having inferred a type for the righthand side of f the type

the mo dule that needs the instance declaration is able to

checker must generalise this type to obtain the p olymorphic

see it If this is so then failure can b e rep orted immedi

type for f Here are several p ossible types for f

ately regardless of the context reduction strategy

f Ord a a Bool

f Ord a Eq a a Bool

f Ord a Eq a Eq a a Bool

Tautological constraints

Which of these types is inferred dep ends on how much con

text reduction is done b efore generalisation a topic we dis

A tautological constraint is one that is entailed by the empty

cuss later Section For the present we only need note

context For example given the standard instance dec

a that there is a choice to b e made here and b that the

larations Ord Int is a tautological constraint b ecause

time that choice is crystallised is at the moment of general

the instance declaration for Ord a together with that for

isation

Ord Int allow us to conclude that fg fOrd Intg

What we mean by b is that it makes no dierence whether

A ground constraint is one that mentions no type variables

context reduction is done just b efore generalising f or just

It is clear that a ground constraint is erroneous that is

after inferring the type of the subexpression ysz or

cannot match any instance declaration or is tautological

anywhere in b etween all that matters is how much is done

It is less obvious that a tautological constraint do es not have

b efore generalisati on

to b e ground Consider

5

In Gofer an instance declaration instanc e P C where

brings ab out the axiom C `` P b ecause the representation in Gofer

Overlapping instance declarations

of a dictionary for C contains subdictionaries for P In retrosp ect

this was probably a p o or design decision b ecause it is not always very

intuitive Moreover it was later discovered that this is incompatible

Consider these declarations

with overlapping instances while either one is acceptable on its own

the combination results in an unsound The Gofer type

class MyShow a where

system still suers from this problem to day b ecause of concerns that

removing supp ort for either feature would break a lot of existing co de

myShow a String

hence supp ort a combination of dierent prim instance MyShow a MyShow a where

itive features This same approach has proved myShow myShow

to b e very exible in other recent work Jones instance MyShow Char where

a Liang Hudak Jones myShow myShow

Here the programmer wants to use a dierent metho d for

To combine the features of monads we introduce a notion

myShow when used at Char than when used at other types

of a monad transformer the idea is that a monad trans

We say that the two instance declarations overlap b ecause

former t takes a monad m as an argument and pro duces a

there exists a constraint that matches b oth For example

new monad t m as a result that provides all of the com

the constraint MyShow Char matches b oth declarations In

putational features of m plus some new ones added in by the

general two instance declarations

transformer t

instance P Q where

class MonadT t where

instance P Q where

lift Monad m m a t m a

are said to overlap if Q and Q are uniable This deni

For example the state monad transformer that can add

tion is equivalent to saying that there is a constraint Q that

state to any monad

matches b oth Q and Q Overlapping instance declarations

are illegal in Haskell but p ermitted in Gofer

newtype StateT s m a StateT s m as

When during context reduction a constraint matches two

instance MonadT StateT s where

overlapping instance declarations which should b e chosen

instance Monad m

We will discuss this question in Section but for now we

StateMonad StateT s m s where

address the question of whether or not overlapping instance

declarations are useful We give two further examples

Critically we also need to know that any prop erties enjoyed

by the original monad are also supp orted by the trans

formed monad We can capture this formally using

Default metho ds

instance MonadT t StateMonad m s

StateMonad t m s where

One application of overlapping instance declarations is to

update f lift update f

dene default metho ds Haskell has the following stan

dard classes

Note the overlap with the previous instance declaration

which plays an essential role Dening monad transformers

class Monad m where

in this way allows us to build up comp osite monads with

m a a m b m b

automatically generated liftings of the imp ortant op erators

return a m a

For example

class Functor f where

f StateMonad m Int StateMonad m Char

map a b f a f b

Int Char m IntChar

f x y do x update const x

Now in any instance of Monad there is a sensible denition

y update const y

of map an idea we could express like this

return xy

instance Monad m Functor m where

Later we might call this function with an integer and a char

map f m f x x m

acter argument on a monad that weve constructed using the

following

These instance declarations overlap with all other instances

of Functor Whether this is the b est way to explain that

type M StateT Int ErrorT State Char

an instance of Monad has a natural denition of map is de

batable

Notice that the argument of the StateT monad trans

former is not State Char but rather the enriched monad

ErrorT State Char assuming that ErrorT is another

monad transformer Now the overloading mechansims will

Monad transformers

automatically make sure that the rst call to update in f

takes place in the outermost Int state monad while the sec

A second applicati on of overlapping instance declarations

ond call will b e lifted up from the depths of the innermost

arises when we try to dene monad transformers The idea

Char state monad

is given by Jones

In fact we will take a more forwardthinking

The ambiguity problem

approach and use the constructor class mecha

nisms to dene dierent families of monads each

As we observed earlier some programs have ambiguous typ

of which supp orts a particular collection of sim

ings The classic example is show read s where dier

ple primitives The b enet of this is that later

ent choices for the intermediate type the result of the read

we will want to consider monads that are simulta

might lead to dierent results Programs with ambiguous

neously instances of several dierent classes and

typings are therefore rejected by Haskell

Next we give some ground rules ab out the form of class Preliminary exp erience however is that multiparameter

declarations A class declaration takes the form type classes give new opp ortunities for ambiguity Is there

any way to have multiparameter type classes without risk

class P C where op Q

1 n

ing ambiguity Our answer here is no One approach

that has b een suggested to the ambiguity problem in single

If multiparameter type classes are prohibited then n

parameter type classes is to insist that all class op erations

If S is one of the constraints app earing in the

1 m

take as their rst argument a value of the classs type Oder

context P we say that S is a superclass of C We insist on

sky Wadler Wehr Though it is theoretically at

the following

tractive there are to o many useful classes that disob ey this

constraint Num for example and overloaded constants in

There can b e at most one class declaration for each general so it has not b een adopted in practice It is also

class C not clear what the rule would b e when we move to con

structor classes so that the classs type variable ranges

Throughout the program all uses of C are applied to

over type constructors

n arguments

If no workable solution to the ambiguity problem has b een

must b e distinct type variables

1 n

found for single parameter classes we are not optimistic that

one will b e found for multiparameter classes

TV P f g That is P must not mention

1 n

any type variables other than the

i

The sup erclass hierarchy dened by the set of class

Design choices

declarations must b e acyclic This restriction is not ab

solutely necessary but the application s for cyclic class

structures are limited and it helps to keep things sim

We are now ready to discuss the design choices that must b e

ple embo died in a typeclass system of the kind exemplied by

Haskell Our goal is to describ e a design space that includes

Haskell Gofer and a number of other options b eside While

Next we give rules governing instance declarations which

we express opinions ab out which design choices we prefer

have the form

our primary goal is to give a clear description of the design

space rather than to prescrib e a particular solution

instance P C where

1 n

We call P the instance context the instance types

1 n

and C the head of the instance declaration Like

1 n

The ground rules

Haskell we insist that

S Type systems are a huge design space and we only have

TV P TV that is the instance context must

i

space to explore part of it in this pap er In this section we

not mention any type variables that are not mentioned

briey record some design decisions currently embo died in

in the instance types

Haskell that we do not prop ose to meddle with Our rst

set of ground rules concern the larger setting

We discuss the design choices related to instance declara

tions in Sections and

We want to retain Haskells typeinference prop erty

Thirdly we require the following rule for types

We want type inference to b e decidable that is the

compiler must not fail to terminate

If P is a type then TV P TV If the

We want to retain the p ossibili ty of separate compila

context P mentions any type variables not used in

tion

then any use of a value with this type is certain to b e

ambiguous

We want all existing Haskell programs to remain legal

and to have the same meaning

Fourthly we will assume that despite separate compilation

We seek a coherent type system that is every dierent

instance declarations are globally visible The reason for this

valid typing derivation for a program leads to a result

is that we want to b e able to rep ort an error if we encounter

ing program that has the same dynamic semantics

a constraint that cannot match any instance declaration

For example consider

The last p oint needs a little explanation We have already

f x c x

seen that the way in which context reduction is p erformed

aects the dynamic semantics of the program via the con

Type inference on f gives rise to the constraint Num Char

struction and use of dictionarie s other op erational mo dels

If instance declarations are not globally visible then we

will exp erience similar eects It is essential that the way in

would b e forced to defer context reduction in case f is

which the typing derivation is constructed there is usually

called in another mo dule that has an instance declaration

more than one for a given program should not aect the

for Num Char Thus we would have to infer the following

meaning of the program

type for f

f Num Char Char Char

Instead what we really want to rep ort an immediate error Similar problems o ccur with multiparameter classes if we

when typechecking f insist that the arguments of each constraint in a context

must b e variables a natural generalization of the single

So if instance declarations are not globally visible many

parameter notion of a simple context For example one

missinginstan ce errors would only b e rep orted when the

can imagine inferring a context such as fStateMonad IO g

main mo dule is compiled an unacceptable outcome Ex

where is a type variable If we then want to generalise

plicit type sigatures might force earlier error rep orts how

over we would obtain a function whose type was of the

ever Hence our ground rule In practice though we can

form StateMonad IO If such a type was illegal then

get away with something a little weaker than insisting that

as with the previous example we would b e forced to reject

every instance declaration is visible in every mo dule for

the program even though it has a sensible principal type in

example when compiling a standard library one do es need

a slightly richer system

instance declarations for unrelated userdened types

The choices for the allowable contexts in types seem to b e

Lastly we have found it useful to articulate the following

these

principle

Choice a Haskell the context of a type must b e sim

Adding an instance declaration to welltyped program

ple with some extended denition of simple

should not alter either the static or dynamic seman

tics of the program except that it may give rise to

Choice b Gofer there are no restrictions on the con

an overlappinginstanc edecl arati on error in systems

text of a type

that prohibit overlap

Choice c something in b etween these two For example

we might insist that the context in a type is reduced

The reason for this principle is to supp ort separate compila

as much as p ossible But then a legal type signature

tion A separately compiled library mo dule cannot p ossibly

might b ecome illegal if we introduced a new instance

see all the instance declarations for all the p ossible client

declaration b ecause then the type signature might no

mo dules So it must b e the case that these extra instance

longer b e reduced as much as p ossible

declarations should not inuence the static or dynamic se

mantics of the library except if they conict with the in

stance declarations used when the library was compiled

Decision How much context reduc

tion

Decision the form of types

Decision how much context reduction should be done be

Decision what limitations if any are there on the form

fore generalisation Haskell and Gofer make very dierent

of the context of a type In Haskell types whether

choices here Haskell takes an eager approach to context

inferred or sp ecied in a type signature must b e of the

reduction doing as much as p ossible b efore generalisation

form P where P is a simple context We say that a

while Gofer takes a lazy approach only using context reduc

context is simple if all its constraints are of the form C

tion to eliminate tautological constraints

where C is a class and is a type variable

It turns out that this choice has a whole raft of consequences

This design decision was defensible for Haskell which

as Jones Chapter discusses in detail These con

lacked constructor classes but seems demonstrably wrong

sequences mainly concern pragmatic matters such as the

for Haskell For example consider the denition

complexity of types or the eciency of the resulting pro

gram It is highly desirable that the choice of how much

g xs map not xs xs

context reduction is done when should not aect the mean

The right hand side of the denition has the type

ing of the program It is bad enough that the meaning of the

6

f Bool Bool and context fFunctor f Eq f Boolg

program inevitably dep ends on the resolution of overload

Because of the second constraint here this cannot b e re

ing Odersky Wadler Wehr It would b e much

duced to a simple context by the rules in Figure and

worse if the programs meaning dep ended on the exact way

Haskell rejects this denition as illtyped In fact if we

in which the overloading was resolved that is if the type

insist that the context in a type must b e simple the function

system were incoherent Section

g has many legal types such as Bool Bool but no

Here then are the issues aecting context reduction

principal or most general type If instead we allow non

simple contexts in types then it has the p erfectly sensible

principal type

Context reduction usual ly leads to simpler contexts

which are p erhaps more readily understo o d and writ

g Functor f Eq f Bool f Bool Bool

ten by the programmer In our earlier example Ord a

is simpler than fOrd a Eq a Eq ag

In short Haskell lacks the principal type prop erty

namely that any typable expression has a principal type

Occasionall y however a simpler context might b e

but it can b e regained by allowing richer contexts in types

less natural Supp ose we have a data type Set with

This is not just a theoretical nicety it directly aects the

an op eration union and an Ord instance Jones

expressiveness of the language

Section

6

The denition of the class Functor was given in Section

data Set a f Ord a a a Bool

A dictionary for Ord a will b e passed to f which will

union Eq a Set a Set a Set a

construct a dictionary for Ord a In this example

though f is called twice at the same type and the two

instance Eq a Ord Set a where

calls will indep endently construct the same Ord a

dictionary We could obtain more sharing ie e

Now consider the following function denition

ciency by p ostp oning the context reduction inferring

instead the following type for f

f x y if xy then y else x union y

f Ord a a a Bool

With context reduction fs type is inferred to b e

Now f is passed a dictionary for Ord a and this

f Eq a Set a Set a Set a

dictionary can b e shared b etween the two calls of f

whereas without context reduction we would infer

Because context reduction is p ostp oned until the top

level in Gofer this sharing can encompass the whole

f Ord Set a Set a Set a Set a

program and only one dictionary for each classtype

combination is ever constructed

One can argue that the latter is more natural since

Type signatures interact with context reduction

it is clear where the Ord constraint comes from while

Haskell allows us to sp ecify a type signature for a func

the former contains a slightly surprising Eq constraint

tion Dep ending on how context reduction is done and

that results from the unrelated instance declaration

what contexts are allowed in type signatures this type

Context reduction often but not always reduces the

might b e more or less reduced than the inferred type

number of dictionaries passed to functions In the run

For example if full context reduction is normally done

ning example of Section doing context reduction b e

b efore generalisation then is this a valid type signa

fore generalisation allowed us to pass one dictionary to

ture

f instead of three

f Eq a

Sometimes though a simpler context might have

more constraints ie more dictionaries to pass in

That is can a type signature decrease the amount of

a dictionarypassi ng implementation For example

context reduction that is p erformed In the other di

given the instance declaration

rection if context reduction is not usually done at gen

eralisation then is this a valid type signature

instance Eq a Eq b Eq ab where

f Eq a

the constraint Eq ab would reduce to fEq a Eq bg

which may b e simpler but certainly is not shorter

where fs righthand side generates a constraint

Eq a That is can a type signature increase the

Context reduction eliminates tautological constraints

amount of context reduction that is p erformed

For example without context reduction the function

Context reduction is necessary for polymorphic recur

double x x xInt

sion One of the new features in Haskell is the

ability to dene a recursive function in which the re

would get the type

cursive call is at a dierent type than the original call

a feature that has proved itself useful in the ecient en

double Num Int Int Int

co ding of functional data structures Okasaki

For example consider the following nonuniformly re

This type means that a dictionary for Num Int will b e

cursive function

passed to double which is quite redundant It it in

variably b etter to reduce fNum Intg to fg using the

f Eq a a a Bool

Int instance of Num The evidence that Int is an

f x y if x y then True

instance of Num takes the form of a global constant

else f x y

dictionary for Num Int This example uses a ground

constraint but the same reasoning applies to any tau

It is not p ossible to avoid all runtime dictionary con

tological constraint

struction in this example b ecause each call to recur

Delaying context reduction increases sharing of dictio

sive f must use a dictionary of higher type and there

naries Consider this example

is no static b ound to the depth of recursion It fol

lows that the strategy of defering all context reduc

let

tion to the top level thereby ensuring a nite number

f xs y xs y

of dictionaries cannot work The type signature is

in

necessary for the type checker to p ermit p olymorphic

f xs y f xs z

recursion and it in turn forces reduction of the con

straint Eq a that arises from the recursive call to

Haskell will infer the type of f to b e f

Context reduction aects typability Consider the fol We should note that be rule out Choice a for type signa

lowing contrived program tures Furthermore as we shall see in Section Choices

a and e rule out overlapping instance declarations

data Tree a Nil Fork Tree a Tree a

The intent in Choice e is to leave as much exibili ty as p os

sible to the compiler so that it can make the most ecient

f x let silly y yNil

choice while still giving a welldened static and dynamic

in x

semantics for the language

If there is no Eq instance of Tree then the program is

arguably erroneous since silly p erforms equality at

So far as the static semantics is concerned when con

type Tree But if context reduction is deferred silly

text reduction is p erformed do es not change the set of

will without complaint b e assigned the type

typable programs

Concerning the dynamic semantics in the absence of

silly Eq Tree a a Bool

overlapping instance declarations a given constraint

can only match a unique instance declaration

Then since silly is never called no other type error

will result In short the denition of which programs

are typable and which are not dep ends on the rules for

context reduction

Decision overlapping instance dec

Context reduction conicts with the use of overlapping

larations

instances This is a bigger topic and we defer it until

Section

Decision are instance declarations with overlapping but

not identical instance types permitted See Section

Bearing in mind this amazingly large set of issues there

If overlapping instances are p ermitted we need a rule that

seem to b e the following p ossible choices

sp ecies which instance declaration to choose if more than

one matches a particular constraint Gofers rule is that the

Choice a Haskell eager reduce every context to a

declaration that matches most closely is chosen In general

simple context b efore generalisation However as we

there may not b e a unique such instance declaration so

have seen this may mean that some p erfectly reason

further rules are required to disambiguate the choice for

able programs are rejected as b eing illtyped

example Gofer requires that instance declarations may only

overlap if one is a substitution instance of the other

Choice b lazy do no context reduction at all until the

constraints for the whole program are gathered to

Unfortunately this is not enough As we mentioned ab ove

gether then reduce them This is satisfyingly decisive

there is a fundamental conict b etween eager or unsp eci

but it gives rise to pretty stupid types such as

ed context reduction and the use of overlapping instances

To see this consider the denition

Eq a Eq a Eq a a Bool

Num Int Show Int Int String

let

f x myShow xx

Choice c Gofer fairly lazy do context reduction b e

in

fore generalisatio n but refrain from using rule inst

f c f TrueFalse

except for tautological constraints If overlapping in

stances are p ermitted then change tautological to

where myShow was dened in Section If we do full con

ground A variant would b e to refrain from using

text reduction b efore generalisin g f we will b e faced with a

super as well

constraint MyShow a arising from the use of myShow Un

der eager context reduction we must simplify it presumably

Choice d Gofer p olymorphic recursion like c

using the instance declaration for MyShow a to obtain the

but with the added rule that if there is a type sig

type

nature the inferred context must b e entailed by the

context in the type signature and the variable b eing

f MyShow a a String

dened is assigned the type in the signature through

If we do so then every call to f will b e committed to the

out its scop e This is enough to make the choice com

myShow metho d However supp ose that we rst p erform

patible with p olymorphic recursion which c is not

a simple program transformation inlini ng f at b oth its call

Choice e relaxed leave it unsp ecied how much con

sites to obtain the expression

text reduction is done b efore generalisation That is

myShow c myShow TrueFalse TrueFalse

if the actual context of the term to b e generalised is

P then the inferred context for the generalised term

Now the two calls distinct calls to myShow will lead to the

is P or any context that P reduces to The same rule

constraints MyShow Char and MyShow Bool resp ectively

for type signatures must apply as in d for the same

the rst will lead to a call of myShow while second will lead

reason To avoid the problem of item we can require

to a call of myShow A simple program transformation has

that an error is rep orted as so on as a generalisation

changed the b ehaviour of the program

step encounters a constraint that cannot p ossibly b e

satised even if that constraint is not reduced

Now consider the original program again If instead we de Haskell has only singleparameter type classes hence

ferred context reduction we would infer the type n Furthermore Haskell insists that the single type

is a simple type that is a type of the form T

1 m

f MyShow a a String

where T is a type constructor and are distinct type

1 n

variables This decision is closely b ound up with Haskells

Now the two calls to f will lead to the constraints

restriction to simple contexts in types Section Why

MyShow Char and MyShow Bool as in the inlined case

Because faced with a constraint of the form C T there

leading to calls to myShow and myShow resp ectively In

is either a unique instance declaration that matches it in

short eager context reduction in the presence of overlapping

which case the constraint can b e reduced or there is not in

instance declarations can lead to premature committment to

which case an error can b e signaled If were allowed to

a particular instance declaration and consequential loss of

b e other than a type variable then more than one instance

simple sourcelanguage program transformations

declaration might b e a p otential match for the constraint

For example supp ose we had

Overlapping instances are also incompatible with the reduc

tion of nonground tautological constraints For example

instance Foo Tree Int where

supp ose we have the declaration

instance Foo Tree Bool where

instance Monad ST s where

Note that these two do not overlap Given the constraint

Foo Tree for some type variable we cannot decide

and we are trying to simplify the context fMonad ST g It

which instance declaration to use until we know more ab out

would b e wrong to reduce it to fg b ecause there might b e

If we are generalisin g over we will therefore end up

an overlapping instance declaration

with a function whose type is of the form

instance Monad ST Int where

Foo Tree

This inabili ty to simplify nonground tautological con

Since Haskell do es not allow such types b ecause the con

straints has in practice caused Gofer some diculties

text is not simple it makes sense for Haskell also to restrict

when implementing lazy state threads Launchbury Pey

instance types to b e simple types If types can have more

ton Jones Briey runST insists that its argument

general contexts however it is not clear that such a restric

has type ST while the argument type would b e in

tion makes sense

ferred to b e Monad ST ST

We have come across examples where it makes sense for

To summarise if overlapping instances are p ermitted then

the instance types not to b e simple types Section

the meaning of the program dep ends in detail on when con

gave examples in which the instance type was just a type

text reduction takes place To avoid loss of coherence we

variable although this was in the context of overlapping

must sp ecify when context reduction takes place as part of

7

instance declarations Here is another example

the type system itself

class Liftable f where

One p ossibili ty is to defer reduction of any constraint that

lift a f a

can p ossibly match more than one instance declaration

lift ab f a f b

That restores the ability to p erform program transforma

lift abc f a f b f c

tions but it interacts p o orly with separate compilation A

separatelycompil ed library might not see all the instances

instance Liftable f Num a Num f a where

of a given class that a client mo dule uses and so must con

fromInteger lift fromInteger

servatively assume that no context reduction can b e done at

negate lift negate

all on any constraint involving a type variable

lift

So the only reasonable choices are these

The instance declaration is entirely reasonable it says

that any liftable type constructor f can b e used to con

Choice a prohibit overlapping instance declarations

struct a new numeric type f a from an existing numeric

Choice b p ermit instance declarations with overlapping

type a Indeed these declarations precisely generalises the

but not identical instance types provided one is a

Behaviour class of Elliott Hudak and we have en

substitution instance of the other but restrict all uses

countered other examples of the same pattern You will

of the inst rule Figure to ground contexts C P

probably have noticed that lift is just the map from the

This condition identies constraints that can match

class Functor p erhaps Functor should b e a sup erclass of

at most one instance declaration regardless of what

Liftable A disadvantage of Liftable is that now the

further instance declarations are added

Haskell types for Complex and Ratio must b e made instances

of Num indirectly by making them instances of Liftable

This seems to work ne for Complex but not for Ratio In

cidentally we could overcome this problem if we had over

Decision instance types

lapping instances thus

instance Liftable f Num a Num f a where

Decision in the instance declaration

instance Num a Num Ratio a where

instance P C where

1 n

Another reason for wanting nonsimple instance types is

what limitations if any are there on the form of the instance

7

Suggested by John Matthews types

1 n

8

can the instance head contain repeated type variables when using old types for new purp oses For example sup

i

This decision is really part of Decision but it deserves p ose we want to dene the class of moveable things

separate treatment

class Moveable t where

Consider this instance declaration which has a rep eated move Vector t t

type variable in the instance type

Now let us make p oints moveable What is a p oint Perhaps

instance Foo aa where just a pair of Floats So we might want to write

In Haskell this is illegal but there seems no technical rea instance Moveable Float Float where

son to exclude it Furthermore it is useful the VarMonad

or even

instance for ST in Section used rep eated type variables

as did the Iso example in Section

type Point Float Float

instance Moveable Point where

Permitting rep eated type variables in the instance type of

an instance declaration slightly complicates the pro cess of

Unlike the Liftable example it is p ossible to manage with

matching a candidate instance declaration against a con

simple instance types by making Point a new type

straint requiring full matching ie oneway unication

a wellunderstoo d algorithm For example when matching

newtype Point MkPoint Float Float

the instance head Foo against a constraint Foo

1 2

instance Moveable Point where

one must rst bind to and then check for equality b e

1

but that might b e tiresome for example unzip split a list

tween the nowbound and

2

of p oints into their xco ordinates and yco ordinates

Choice a p ermit rep eated type variables in an instance

Choice a Haskell the instance types must all b e

head

i

simple types

Choice b prohibit rep eated type variables in an instance

Choice b each of the instance types is a simple type

head

i

or a type variable and at least one is not a type vari

able The latter restriction is necessary to ensure that

context reduction terminates

Decision instance contexts

Choice c at least one of the instance types must not

i

b e a type variable

Decision in the instance declaration

instance P C where

Choice c would p ermit the Liftable example ab ove It

1 n

would also p ermit the following instance declarations

what limitations if any are there on the form of the instance

instance D T Int a where

context P

instance D T Bool a where

As mentioned in Section we require that TV P

S

even if overlapping instances are prohibited provided of

TV However Haskell has a more drastic restriction

i

course there was no instance for D T a b It would also

it requires that each constraint in P b e of the form C

allow strangelo oking instance declarations such as

where is a type variable An imp ortant motivation for

a restriction of this sort is the need to ensure termination

instance C a Int where

of context reduction For example supp ose the following

declaration was allowed

which in turn make the matching of a candidate instance

declaration against a constraint a little more complicated

instance C a C a where

although not much

The trouble here is that for context reduction to terminate

If overlapping instances are p ermitted then it is not clear

it must reduce a context to a simpler context This instance

whether choices b and c lead to a decideable type system

declaration will reduce the constraint C to C

If overlapping instances are not p ermitted then seem to b e

which is more complicated and context reduction will di

no technical ob jections to them and the examples given

verge Although they do not seem to o ccur in practical

ab ove suggest that the extra expressiveness is useful

application s instance declarations like this are p ermitted in

Goferwith the consequence that its type system is in fact

undecidable

Decision rep eated type variables in

In short it is essential to place enough constraints on the

instance heads

instance context to ensure that context reduction converges

To do this we need to ensure that something gets smaller

Decision in the instance declaration

in the passage from C to P Haskells restriction to

1 n

simple contexts certainly ensures termination b ecause the

instance P C where

1 n

argument types are guaranteed to get smaller In princi

ple instance declarations with irreducibl e but nonsimple

8

Suggested by Simon Thompson

contexts might make sense

instance Monad t m Foo t m where it contains free type variables

9

We have yet to nd any convincing examples of this How it do es not match any instance declaration

ever if context reduction is deferred Choices bc then we

it can b e made to match an instance declaration by in

must p ermit nonsimple instance contexts For example

stantiating some of the constraints free type variables

data Tree a Node a Tree a

no matter what other legal instance declarations are

instance Eq a Eq Tree a Eq Tree a where

added there is only one instance declaration that the

Node v ts Node v ts

constraint can b e made to match in this way

v v ts ts

Here if we are not p ermitted to reduce the constraint

If all these things are true an attractive idea is to improve

Eq Tree a it must app ear in the instance context

the constraint by instantiating the type variables in the con

straint so that it do es match the instance declaration This

Lastly if the constraints in P involve only type variables

makes some programs typable that would not otherwise b e

when multiparameter type classes are involved we must also

so It do es not compromise any of our principles b ecause

ask whether a single constraint may contain a rep eated type

the last condition ensures that even adding new instance

variable thus

declarations will not change the way in which improvement

instance Foo a a Baz a where

is carried out

There seems to b e no technical reason to prohibit this

Improvement was introduced by Jones b A full dis

cussion is b eyond the scop e of this pap er The conditions

are quite restrictive so it is not yet clear whether it would

Choice a constraints in the context of an instance dec

improve enough useful programs to b e worth the extra eort

laration must b e of the form C with the

1 n i

distinct

Choice a no improvement

Choice b as for Choice a except without the require

ment for the to b e distinct

Choice b allow improvement in some form

i

Choice c something less restrictive but with some way

Choice b would obviously need further elab oration b efore

of ensuring decidabil ity of context reduction

this design decision is crisply formulated

Decision what sup erclasses are p er

Decision Class declarations

mitted

Decision what limitations if any are there on the con

texts in classmember type signatures Presumably class

Decision in a class declaration

member type signatures should ob ey the same rules as any

other type signature but Haskell adds an additional restric

class P C where op Q ;

1 n

tion Consider

what limitations beyond those in Section are there on

class C a where

the form of the superclass context P Haskell restricts P

op a a

to consist of constraints of the form D where

1 m i

op Eq a a a

must b e a member of f g and all the must b e

1 n i

distinct But what is wrong with this

In Haskell the type signature for op would b e illegal b e

cause it further constrains the class type variable a There

class Foo t m Baz t m where

seems to b e no technical reason for this restriction It is sim

Also in this case there seems to b e no technical reason to

ply a nuisance to the Haskell sp ecication implementation

prohibit this

and o ccasionally programmer

Choice a constraints in the sup erclass context must b e

Choice a Haskell the context in a classmember type

as in Haskell ie the constraints are of the form

signature cannot mention the class type variable in

D with the distinct and a subset of the

1 n i

addition it is sub ject to the same rules as any other

type variables that o ccur in the class head

type signature

Choice b no limitations on sup erclass contexts except

Choice b the type signature for a classmember is sub

those p ostulated in Section

ject to the same rules as any other type signature

9

Recall that matching a constraint against an instance declaration

is a oneway unication we may instantiate type variables from the

instance head but not those from the constraint

Decision improvement

Supp ose that we have a constraint with the following prop

erties

is not satisfactory as it forces us to pass several dictionarie s Other avenues

say StateMonad State Int StateMonad State Bool

where they are really the same What we really want is

While writing this pap er a number of other extensions to

to use universal quantication

Haskells typeclass system were suggested to us that seem

to raise considerable technical diculties We enumerate

class forall s Monad m s

them in this section identifying their diculties

StateMonad m where

get m s s

set s m s

Anonymous type synonyms

but that means that the type system would have to han

dle constraints with universal quantication a substantial

When exp osed to multiparameter type classes and in par

complication

ticular higher order type variables programmers often seek

Another ground rule in this pap er is the restriction to acyclic

a more expressive type language For example supp ose we

sup erclass hierarchies Gofer puts no restriction on the form

have the following two classes Foo and Bar

of predicates that may app ear in sup erclass contexts in par

class Foo k where f k a a

ticular it allows mutually recursive class hierarchies For ex

class Bar k where g k b b

ample the Iso class example of Section can b e written

in a more elegant way if we allow recursive classes

and a concrete binary type constructor

class Iso b a Iso a b where iso a b

data Baz a b

The sup erclass constraint ensures that when a type a is iso

Then we can easily write an instance declaration that de

morphic to b then type b is isomorphic to a Needless to

clares Bar a to b e a functor thus

say that such class declarations easily give lead to an unde

cidable type system

instance Functor Baz a where

map

But supp ose Baz is really a functor in its rst argument

Controling the scop e of instances

Then we really want to say is

One sometimes wishes that it was p ossible to have more

type Zab b a Baz a b

than one instance declaration for the same instance type

instance Functor Zab b where

an extreme case of overlap For example in one part of the

map

program one might like to have an instance declaration

However Haskell prohibits partiallyapp li ed type synon

instance Ord T where lessThanT

myms and for a very go o d reason a partiallyappl ie d type

synonym is in eect a lambda abstraction at the type level

and elsewhere one might like

and that takes us immediately into the realm of higherorder

unication and minimises the likeliho o d of a decidable type

instance Ord T where greaterThanT

system Jones a Section It might b e p ossible to

incorp orate some form of higherorder unication eg along

As evidence for this notice that several Haskell standard

the lines of Miller but it would b e a substantial new

library functions such as sortBy take an explicit compar

complication to an already sophisticated type system

ison op erator as an argument reecting the fact that the

Ord instance for the data type involved might not b e the

ordering you want for the sort Having multiple instance

declarations for the same type is however fraught with the

Relaxed sup erclass contexts

risk of losing coherence at the very least it involves strict

control over which instance declarations are visible where

One of our ground rules in this pap er is that the type vari

It is far from obvious that controlling the scop e of instances

ables in the context of a class declaration must b e a subset

is the right way to tackle this problem functors as in ML

of the type variables in the class head This rules out dec

lo ok more appropriate

larations like

class Monad m s StateMonad m where

get m s s

Relaxed type signature contexts

set s m s

In programming with type classes it is often the case

The idea here is that the context indicates that m s should

that we end up with an ambiguous type while we

b e a monad for any type s Rewriting this denition by

know that in fact it is harmless For example know

overloading on the state as well

ing all instance declarations in the program we might

b e sure that the ambiguous example of Section

class Monad m s StateMonad m s where

iso iso Eq b Iso Int b Bool has the

get m s s

same value irresp ective of the choice for b Is it p ossible

set s m s

to mo dify the type system to deal with such cases

K Chen P Hudak M Odersky June Paramet Conclusion

ric type classes in ACM Symp osium on Lisp and

Functional Programming Snowbird ACM

Sometimes a type system is so nely balanced that virtually

any extension destroys some of its more desirable prop er

C Elliott P Hudak June Functional reactive ani

ties Haskells type class system turns out not to have the

mation in Pro c International Conference on Func

prop erty there seems to b e sensible extensions that gain

tional Programming Amsterdam ACM

expressiveness without involving ma jor new complications

P Hudak SL Peyton Jones PL Wadler Arvind B Boutel

We have tried to summarise the design choices in a fairly

J Fairbairn J Fasel M Guzman K Hammond J

unbiased manner but it is time to nail our colours to the

Hughes T Johnsson R Kieburtz RS Nikhil W

mast The following set of design choices seems to dene

Partain J Peterson May Rep ort on the

an upwardcompatible extension of Haskell without losing

functional programming language Haskell Version

anything imp ortant

SIGPLAN Notices

Permit multiparameter type classes

MP Jones Jan a A system of constructor classes

overloading and implicit higherorder p olymor

Permit arbitrary constraints in types and type signa

phism Journal of Functional Programming

tures Choice b

Use the inst contextreduction rule only when forced

MP Jones June b Simplifyi ng and improving qual

by a type signature or when the constraint is tauto

ied types in Pro c Functional Programming

logical Choice d Choice e is also viable

Languages and Computer Architecture La Jolla

Prohibit overlapping instance declarations

ACM

Choice a

MP Jones May The implementation of the Gofer

Permit arbitrary instance types in the head of an in

functional programming system

stance declaration except that at least one must not

YALEUDCSRR Department of Computer

b e a type variable Choice c

Science Yale University

Permit rep eated type variables in the head of an in

MP Jones May Functional programming with over

stance declaration Choice a

loading and higherorder p olymorphism in First

Restrict the context of an instance declaration to men International Spring School on Advanced Func

tion type variables only Choice b tional Programming Techniques Bastad Sweden

SpringerVerlag LNCS

No limitation s on sup erclass contexts Choice b

MP Jones Nov Qualied types theory and practice

Prohibit improvement Choice a

Cambridge University Press

Permit the class variables to b e constrained in class

S Kaes Jan Parametric overloading in p olymor

member type signatures Choice b

phic programming languages in th ACM Sym

p osium on Principles of Programming Languages

Our hop e is that this pap er will provoke some wellinformed

ACM

debate ab out p ossible extensions to Haskells type classes

We particularl y seek a wider range of examples to illustrate

J Launchbury SL Peyton Jones Dec State in

and motivate the various extensions discussed here

Haskell Lisp and Symbolic Computation

Acknowledegements

S Liang P Hudak M Jones Jan Monad transform

ers and mo dular interpreters in nd ACM Sym

p osium on Principles of Programming Languages

We would like to thank Ko en Claessen Benedict Gaster

San Francisco ACM

Thomas Hallgren John Matthews Sergey Mechveliani

Alastair Reid Enno Scholz Walid Taha Simon Thompson

D Miller A logic programming language with

and Carl Witty for helpful feedback on earlier drafts of this

lambda abstraction function variables and simple

pap er Meijer and Peyton Jones also gratefully acknowl

unication Journal of Logic and Computation

edge the supp ort of the Oregon Graduate Institute during

our sabbaticals funded by a contract with US Air Force

M Odersky PL Wadler M Wehr June A second

Material Command FC

lo ok at overloading in Pro c Functional Program

ming Languages and Computer Architecture La

Jolla ACM

References

C Okasaki Sept Purely functional data structures

PhD thesis CMUCS Department of Com

puter Science Carnegie Mellon University

SL Peyton Jones Sept Bulk types with class

in Electronic pro ceedings of the Glas

gow Functional Programming Workshop http

wwwdcsglaacukfpworkshopsfpw

Proceedingshtml

SL Peyton Jones AJ Gordon SO Finne Jan Con

current Haskell in rd ACM Symp osium on

Principles of Programming Languages St Peters

burg Beach Florida ACM

PL Wadler S Blott Jan How to make adho c p oly

morphism less ad ho c in Pro c th ACM Sym

p osium on Principles of Programming Languages

Austin Texas ACM