RalfHinze
InstitutfurInformatik III
Universitat Bonn
Romerstrae164, 53117Bonn, Germany
email: ralfinformatik.uni-bonn.de
SimonPeyton Jones
Mirosoft Researh Ltd
St George House,1 GuildhallSt
CambridgeCB23NH, England
email: simonpjmirosoft.om
Abstrat
Generiprogramming allows youto writea funtionone,
and use it many times at dierent types. A lot of good
foundationalworkongeneri programminghasbeendone.
Thegoalofthispaperistoproposeapratialwayofsup-
porting generiprogramming within the Haskell language,
withoutradiallyhangingthelanguageoritstypesystem.
Thekeyidea istopresent generiprogrammingasariher
languageinwhihto writedefaultmethoddenitions ina
lassdelaration.
Onthe way, weame aross aseparate issue, onern-
ingtype-lassoverloadingwhere higherkindsare involved.
We propose a simple type-lass system extensionto allow
the programmerto writeriher ontextsthan is urrently
possible.
Thispaperappearsintheproeedingsofthe2000Haskell
Workshop,Montreal. ToappearinEletroniNotesinThe-
oretialComputer Siene,Elsevier,2001.
1 Introdution
Ageneri,orpolytypi,funtionisonethattheprogrammer
writesone,butwhihworksovermanydierentdatatypes.
Thestandardexamplesareparsingandprinting,serialising,
takingequality,ordering,hashing,andso on. There islots
ofworkongeneriprogramming[2,8 ,1,6℄.
Inthispaperwepresentthedesignandimplementation
of anextensionto Haskellthat supports generi program-
ming.AtrstsightitmightseemthatHaskell'stypelasses
are inompetition with generi programming| after all,
both onern funtions that work over many data types.
Butwe havefound thattheyanbe ombinedverygrae-
fully,oeringasmoothupwardextensiontoHaskell.
Onthewaywedesribeanorthogonal,butomplemen-
taryidea. Haskellallows oneto denehigher-orderkinded
datatypesforwhihitisimpossibletodene,forexample,
anequality instane. Thisseems unfortunate: onepart of
the language ismore powerful thananother. Wedesribe
amodest extensionof Haskell's type-lass system that re-
movesthisdiÆulty.
Morespeially,ourontributionsarethese:
2 We present the language design for an extension to
Haskellthatsupportsgeneriprogramming(Setions2{
6). Generifuntionsappearsolelyinlassdelarations.
2 We desribe an entirely separate extension that lets
onewrite ertain instanedelarations for higher-order
kinded data types that are simply inexpressible in
Haskell98(Setion7).
2 Wedisusstheimplementationofbothparts.
The rst part of this paper is a follow-up to [4 ℄; the new
ahievementsaredetailedinSetion8.
2 Setting the sene
Inthissetionwesettheontextforourproposal.Webegin
byreviewingHaskell'stype-lassoverloadingmehanism.
2.1 A briefreviewoftype lassoverloading
Haskell supports overloading, based on type lasses. For
example,thePreludedenesthelassEq:
lassEqtwhere
( );(6 ) :: t!t!Bool:
Thisdenestwooverloadedtop-levelfuntions,( )and(6 ),
whosetypesare
( );(6 ) :: (Eqt))t!t!Bool:
Beforeweanuse( )onvaluesof,sayInt,wemustexplain
howtotakeequality overInt values:
instaneEqIntwhere
( ) = eqInt
(6 ) = neInt:
Here we supposethat eqInt::Int !Int !Bool,andsim-
ilarly neInt are provided from somewhere. The instane
delarations says \the ( ) funtion at type Int is imple-
mentedbyeqInt".
Howanwetakeequalityofpairsofvalues? Presumably
byomparingtheir omponents;butthat requiresequality
overtheomponenttypes:
instane(Eqa;Eqb))Eq(a;b)where
(x1;y1) (x2;y2) = (x1 x2)^(y1 y2)
(x1;y1)6 (x2;y2) = (x1 6 x2)_(y16 y2):
Itisabitannoyingtokeephavingtowriteodeforthe(6 )
method,beauseitissimplythenegationoftheodeforthe
( )method,soHaskellallowsyoutowriteadefaultmethod
inthelassdelaration:
lassEqtwhere
( );(6 ) :: t!t!Bool
x16 x2 = not (x1 x2):
Now, ifyougive aninstane delarationfor Eq that laks
a denition for (6 ), Haskell\lls in" the missing method
weanwrite:
instane(Eqa;Eqb))Eq(a;b)where
(x1;y1) (x2;y2) = (x1 x2)^(y1 y2)
andgetjustthesameeetasbefore. Youanevenspeify
adefaultmethodforbothmethods:
lassEqtwhere
( );(6 ) :: t!t!Bool
x
1 x
2
= not(x
1 6 x
2 )
x
1 6 x
2
= not(x
1 x
2 ):
Inaninstanedelaration,youannoweither giveadeni-
tionfor( ),or adenitionfor(6 ),orboth. Ifyouspeify
neither,thenyouwillgetaninniteloop,unfortunately!
If you give an instane delaration without speifying
ode for method op, and the lass hasno default method
forop,theninvokingthemethodwillhalttheprogramwith
anerrormessage. Itisnotaompile-timeerror;sometimes
amethodjustdoesn't makesensefor apartiularinstane
type.
2.2 Overloadingisnot generiprogramming
Haskellasitstandsdoesnotsupportgeneri,orpolytypi,
programming.Inpartiular,supposeyoudeneanewdata
type:
dataWibble = WagIntjWugBool:
Itis \obvious"howto takeequality overWibble,and sup-
portforgeneriprogrammingwouldallowustospeifythis
\obvious"preisely. InHaskell,however,youhavetogivean
expliitinstanedelaration, ontainingtheodeforequal-
ity:
instaneEqWibblewhere
(Wagi1) (Wagi2) = i1 i2
(Wugb1) (Wugb2) = b1 b2
w1 w2 = False:
Crankingoutthissortofboilerplateodeissotiresomethat
Haskellprovidesspeialsupport|theso-alled\deriving"
mehanism|forahandfulofbuilt-inlasses. Inpartiular,
forEqyousay
dataWibble = WagIntjWugBoolderiving(Eq):
The\deriving(Eq)"parttellsHaskelltogeneratethe\ob-
vious"odeforequality.What\obvious"meansisspeied
informally inan Appendixof the languagedenition [15 ℄.
This is all rather ad ho, and in partiular it only works
foraxedsetofbuilt-inlasses(Eq,Ord,Enum,Bounded,
Read,Show,andIx).
2.3 Generalising defaultmethods
Whatwe seek,then,is anautomatimehanismthat \lls
in"asuitableimplementationforthemethodsofaninstane
delaration. But wait a minute! That's what a default
methoddoes! Indeedsobut,as wehavealreadyremarked,
default methods as they stand are too weak. If we write
merely:
instaneEqWibble
wewould,asremarkedearlier, justgetaninniteloop. We
havetoprovidesomerealodesomewhere! What wewant
isariherlanguageinwhihtowritedefaultmethods.That
iswhatweturnourattentiontonow.
Fromalanguage-designpointofview,ourstoryisthis: pro-
viding a riher language for default method denitions in
a lass delaration gives an elegant way to extend Haskell
withthepowerof generiprogramming. Wewilljustifythis
statementmorefullyinSetion9,butrstwemustpresent
ourdesign.
3.1 Twoexamples
Weadoptwithminorhangestheproposalin[4 ℄. Twoex-
ampleswillservetogivetheidea. First,hereistheEqlass
augmentedwithgeneriequality:
lassEqtwhere
( );(6 ) :: t!t!Bool
--generidefaultmethod
( )f1gUnitUnit = True
( )fa+bg(Inlx1)(Inlx2) = x1 x2
( )fa+bg(Inry1)(Inr y2) = y1 y2
( )fa+bg = False
( )fabg(x1::y1)(x2::y2) = x1 x2^y1 y2
--vanilla,non-generidefaultmethod
(6 )x1 x2 = not(x1 x2):
Thisnewlassdelarationontainsanordinary,defaultde-
larationfor(6 ),justasbefore. Thenewfeatureisageneri
denition forequality,distinguishedbytheurlybraeson
theleft handside,whihenloseatype argument. Wewill
studysuhgeneridenitionsinmoredetailinSetion4.2.
Fornow,wesimplyobservethatageneridenitionworks
byindutionoverthestrutureofthetype(writteninurly
braes)atwhihthelassisinstantiated.
Nowweangiveaninstanedelarationlikethis:
instaneEqWibble
without giving ode for either method. Both methods will
be \lled in" from the lass delaration. The ordinary,
non-generidefaultmethod,(6 ),islledinverbatim. The
generidefaultmethod,( ),isspeialisedinawaywewill
desribe, to giveessentially the ode inSetion2.2. That
is,theeetoftheinstanedelarationis exatlyasifwe
hadwritten
instaneEqWibblewhere
(Wagi1) (Wagi2) = i1 i2
(Wugb1) (Wugb2) = b1 b2
w1 w2 = False
w
1 6 w
2
= not (w
1 w
2 ):
Here is another example. The lass Binary has methods
showBinandreadBinthatrespetivelyonvertavaluetoa
listofbitsandvieversa:
dataBit = 0j1
typeBin = [Bit℄
lassBinarytwhere
showBin :: t!Bin
readBin :: Bin!(t;Bin):
Arealimplementationmighthaveamoresophistiatedrep-
resentationfor Bin butthat isaseparate matter. Wean
showBinf1gUnit = [℄
showBinfa+bg(Inlx) = 0:showBinx
showBinfa+bg(Inr y) = 1:showBiny
showBinfabg(x ::y) = showBinx ++showBiny
readBinf1gbs = (Unit;bs)
readBinfa+bg[℄ = error"readBin"
readBinfa+bg(0:bs) = let(x;bs 0
)=readBinbs
in(Inlx;bs 0
)
readBinfa+bg(1:bs) = let(y;bs 0
)=readBinbs
in(Inr y;bs 0
)
readBinfabgbs = let(x;bs
1
)=readBinbs
(y;bs
2
)=readBinbs
1
in((x ::y);bs
2 ):
NotiethatreadBinproduesavalueoftheunknowntypet,
whereasshowBinand( )bothonsumesuhvalues. Again,
weanmakeWibbleaninstaneofBinarybysayingsimply
instaneBinaryWibble:
3.2 Instanes andderiving
Thoughall ofthissoundssimpleenough,ithasinteresting
andimportantonsequenes:
2 Thoughaninstane delarationforalasswithgeneri
methodsisnowratherbrief,itmuststill begiven. Itis
notthease,forexample,thatalltypesbeomeinstanes
of Eq when one gives a generi default methodin the
lassdelarationforEq.
2 Itisnotneessaryfortheinstanedelarationtoappear
inthesamemoduleasthedatatypedelaration,orthe
lassdelaration. Byontrast,inHaskell98aderiving
lause mustbe attahed to the data type delaration.
This separation is useful, beause the lass might not
evenbedenedinthesopewherethetypeisdelared.
2 Theompileronlyllsinamethoddenitionifthepro-
grammeromitsit. Forexample,ifwesaid
instaneEqWibblewhere
(Wag ) (Wag ) = True
w
2 w
2
= False;
thenthis programmer-suppliedodeis,of ourse, used.
Thisisonewayinwhihourproposaldiersfromothers.
Inmostgeneri-programmingsystems,agenerifuntion
works generiallyoveralltypes. Inourdesign, thepro-
grammer anoverride the generi denition ona type-
by-type basis.
Thisabilityisabsolutelyruialtosupportabstratdata
types. For example, asetmaybe represented asabal-
anedtreeinmorethanoneway,andequalitymusttake
aount of this fat. Simply using a generi equality
funtion would take equality of representations, whih
is simplywrong inthis ase. In asimilar way, we an
alsouseordinaryinstanedelarationstospeifywhata
generioperation shoulddoonprimitivetypes,suhas
Char,Int,Double. Inpartiular,ifyouwanttodenea
methodfor typesinvolvingfuntion-spaes, yousimply
supplyaninstanedelarationfor\!".
2 Aderivinglauseannowbeseenasshorthand(albeit
now not so muh shorter) for an instane delaration.
Thereisadierene,though. Consider
dataTreea = Nodea[Treea℄deriving(Eq):
instane(Eqa))Eq(Tree a)
Notethat inaninstane delarationwe mustexpliitly
speifythe ontext (Eq a),whihis inferred automati-
allybythederivingmehanism. Wedisussthisissue
inmoredetailinSetion4.4.
3.3 Generi representation types
Theargumentsinbraesontheleft handsideof ageneri
denitionaretypes. Theideais,ofourse,thatthesegeneri
denitions anbe speialisedfor anypartiulartype. Sup-
pose, for example,wehave adatatype List,andwemake
List aninstaneofBinary:
dataLista = Consa(List a)jNil
instane(Binarya))Binary (Lista):
Howistheompilertollinthemissingmethoddenitions?
First,wedenethegenerirepresentationtype for List,
whihwewillallList Æ
:
typeList Æ
a = (aList a)+1:
WewillhavemoretosayaboutrepresentationtypesinSe-
tion 6.2, butfor nowwe anjustthink of List Æ
as atype
that is more-or-less isomorphi to List, but one that uses
only a small, xed set of type onstrutors, namely unit,
sums,and produts. NotiealsothatList Æ
isnot a reur-
sivetype;itmentionsListontherighthandside,notList Æ
.
Soourgenerirepresentationtypesgivearepresentationfor
justthe\toplevel"ofareursivetype.
Theunit,sum,andproduttypesaredenedlikethis:
data1 = Unit
dataa+b = InlajInrb
dataab = a::b:
Of ourse, 1 is not a legal Haskell type onstrutor, and
nor are inx (+) and (). We give them speial syntax
to distinguish them from their \normal" ounterparts, (),
Either a b, and (a;b), and extendthe syntax of types to
aommodatethem.
In our example, a List is a sum (+) of two types: a
produt()oftheelement typea andaList,andtheunit
type (1). To make the isomorphism expliit, let us write
funtionsthatonverttoandfro 1
:
to-List :: 8a:List Æ
a!Lista
to-List(Inl(x::xs)) = Consx xs
to-List(InrUnit) = Nil
from-List :: 8a:List a!List Æ
a
from-List(Consx xs) = Inl(x::xs)
from-ListNil = InrUnit:
3.4 The generi instanes
Theideaisthatby regarding aList asaList Æ
, thegeneri
odeexplainswhattodo. ThegenerimethodforshowBin,
forexample,sayswhattodoiftheargumentisasum,what
todoifitisaprodut,andwhattodoifitisaunittype.
1
Inthispaperwe willmake quantiationexpliit,eventhough
Haskell98doesnotoerexpliitquantiation. So,inthisexample,
wewriteanexpliit8inthetypesignatureforto-List. Someofour
typesbeomequiteompliated,soithelpstobeabsolutelyertain
wherequantiationistakingplae.
asthreeordinaryinstanedelarations:
instaneBinary 1where
showBinUnit = [℄
readBinbs = (Unit;bs)
instane(Binarya;Binary b))Binary(a+b)where
showBin(Inl x) = 0:showBinx
showBin(Inr y) = 1:showBiny
readBin[℄ = error"readBin"
readBin(0:bs) = let(x;bs 0
)=readBin bs
in(Inlx;bs 0
)
readBin(1:bs) = let(y;bs 0
)=readBinbs
in(Inry;bs 0
)
instane(Binarya;Binary b))Binary(ab)where
showBin(x::y) = showBinx++showBiny
readBinbs = let(x;bs
1
)=readBinbs
(y;bs
2
)=readBinbs
1
in((x::y);bs
2 ):
We desribe these instane delarations for generi repre-
sentationtypesas generi instane delarations. They are
notwritten expliitly by the programmer, butinstead are
derived by the ompiler from a lass delaration that has
generidefaultmethods.Wedisussgeneriinstanedela-
rationsfurtherinSetion4.3.
3.5 Filling inthe missing methods
Weare nowready to saymore preisely howthe ompiler
llsinthe missingmethods. Inthis setion weskeththe
ideausinganexample,whileSetion6dealswiththegeneral
ase.
Whentheprogrammerwrites
instane(Binarya))Binary(Lista)
theompilerwillllinthemethoddelarationsasfollows:
showBinxs = showBin(from-Listxs)
readBinbs = asereadBinbsof
(xs;bs 0
)!(to-Listxs;bs 0
):
LetusfousonthedenitionforshowBin. Itworksintwo
stages:
1. First, from-List::8a:List a ! List Æ
a onverts the
inputlist oftypeList aintoavalueoftypeList Æ
a.
2. Seond, we all the overloaded showBin funtion to
ompletethejob,usingthemethodsofthegeneriin-
stanedelarations.
Atrstthislooksutterlybizarre. Weare deningshowBin
intermsof showBin. Butlookat thedenitiononewould
writebyhand:
instane(Binarya))Binary(List a)where
showBinNil = 0:[℄
showBin(Consxxs) = 1:showBinx++showBinxs:
The rst all is to showBin at the list element type; the
seond is a reursive allto the same showBin at the list
type.
Somethingsimilar happens withthe generi denition.
Here showBin is alled on an argument of type List Æ
a.
Thisisasumtype,sothe suminstane ofBinary kiksin
(Setion3.4). It inturn willallshowBin,oneat type 1,
and one at typea List a. The former has aninstane
makesallstoshowBinattypeaandList a.Buttheformer
isjustliketheshowBinxinthehand-writteninstane,while
thelatterisliketheshowBinxs. Soeverythingworksout.
Letusreturnbrieytotherststepabove. Intheaseof
showBin itwasfairlysimpletoonverttheargumenttoits
generirepresentationtype. OntheotherhandreadBinwas
abitmoreompliatedbeauseitreturnedapair,onlyone
omponentofwhihhadto beonverted. How,ingeneral,
doestheompiler performthis onversion? Wedevote the
wholeofSetion5tothistopi. First,though,weelaborate
ontheprogrammer-visibleaspetsofourdesign.
4 Disussion and elaboration
Wehavenowskethedthebonesofourdesign. Inthisse-
tionweelaborateonsomeofthedetails.
4.1 Construtor namesand reord labels
Annoyingly, unit, sum,and produt are notquite enough.
Consider,forexample,thestandardHaskelllassShow. To
beabletogivegeneridenitionsforshowsPre,thenames
ofthe onstrutors,and theirxities,mustbemadeaes-
sible.
Tothisendweprovideanadditionalgenerirepresenta-
tiontype,oftheform of a where isavalue variable of
typeConDesr andaisatypevariable. ThetypeConDesr
isanewprimitivetypethatomprisesallonstrutornames.
To manipulateonstrutor namesthe following operations
amongothersanbeused|foranexhaustivelistsee[4℄.
dataConDesr --abstrat
dataFixity = Nox jInx IntjInxlIntjInxrInt
onName :: ConDesr!String --primitive
onArity :: ConDesr!Int --primitive
onFixity :: ConDesr!Fixity --primitive
instaneShowConDesr where
show = onName
Using onName and onArity we animplement a simple
variantofHaskell'sShowlass|forthefull-edgedversion
see[4 ℄.
lassShow twhere
show :: t!String
showsPre :: Int!t!String
showx = showsPre 0x
showsPrefa+bgd(Inlx) = showsPre dx
showsPrefa+bgd(Inr y) = showsPre dy
showsPrefof agd(Conx)
=if onArity 0thenshow
elseshowParen (d>10 )
(show ++" "++showsPre10x)
showsPrefabgd(x::y)
=showsPre dx++" "++showsPredy
Therepresentation type of a is dened bythe following
pseudo-Haskelldelaration:
newtypeofa = Cona:
Uniquelyfor Haskell, is avaluethat isarried byatype.
It is best to think of the above delaration as dening a
familyoftypes: foreahthereisatypeonstrutor\of"
of kind? ! ? with a value onstrutor \Con " of type
a !(of a). Now,whydoesthetype of a inorporate
tosupplythisinformationonthevaluelevel.Doingsowould
workfor show,butwouldfailforread:
lassRead twhere
read :: String![(t;String)℄
readfofags = [(Conx;s3)
j(s1;s2) lexs;s1 onName;
(x;s3) read s2℄:
Theimportant point isthat read produes (not onsumes)
thevalue,andyetitrequiresaesstotheonstrutorname.
Haskell allows the programmer to assign labels to the
omponentsofaonstrutor,andthese,too,are neededby
read and show. For the purpose ofpresentation, however,
wehoosetoignoreeldnames.Infat,theyanbehandled
ompletelyanalogouslytoonstrutornames.
4.2 Generilassdelarations
Ingeneral,alassdelarationonsistsofasignature,whih
speiesthetypesofthelassmethods,andanimplementa-
tionpart,whihgivesdefaultdenitionsforthelassmeth-
ods. Thetypesignaturehasthegeneralform:
lasstx)C awhere
op
1 :: Op
1 a
:::
op
n :: Op
n a:
Theimplementationpartonsistsofgeneriandnon-generi
defaultdenitions. Anon-generi denitionisanordinary
Haskelldenition
op = ::::
Ageneridenitionanbe reognisedbythe type patterns
onthe left handside, enlosed inurly braes. It hasthe
shematiform
opf1g = :::
opfa+bg = :::
opfabg = :::
opfofag = ::::
Thetypepatternsaremandatory,sothattheequationsan
be orretly grouped. For example, onsider the generi
denitionof( )givenearlier:
( )f1gUnitUnit = True
( )fa+bg(Inlx1)(Inlx2) = x1 x2
( )fa+bg(Inr y1)(Inry2) = y1 y2
( )fa+bg = False
( )fabg(x1::y1)(x2::y2) = x1 x2^y1 y2:
Withoutthetypepatternsthereisnowaytodeidewhether
theseondbutlastequationbelongstothe(+)ortothe()
ase.
Apart from the type patterns, a generi denition has
exatlytheformofanormalHaskelldenition.
Wenotethefollowing points:
2 Alassdelarationmayspeifyanarbitrarymixtureof
generiandnon-generidefault-methoddelarations. In
the ase of Eq above, ( ) is denedby indutionover
theargumenttype,while(6 )isnon-generi. Thegeneri
andnon-generimethodsmaybemutuallyreursive.
2 Classdelarationsaretheonlyplaethatgenerideni-
tionsappearinourdesign. Thereareno\free-standing"
generi denitions, just as there are no free-standing
withthishoie,butitdoesnotlimitexpressiveness,be-
auseoneanalwaysinventalasstoenapsulateanew
overloadedorgenerifuntion.)
2 At the moment, generi default delarations may only
be givenfor type lasses,that is,for lasseswhosetype
parameterrangesovertypesofkind?. Forexample,we
annotspeifyageneridefaultmethodfortheFuntor
lass:
lassFuntorf where
fmap :: (a!b)!(f a!f b):
Thisistherstextensionweplantoaddinthefuture.
2 Foramulti-parametertypelasstherewouldbemultiple
type arguments. We do notonsider this ompliation
inthispaper.
4.3 Generi instanedelarations
InSetion3.4wesaidthatthegeneridenitionsinalass
delarationare re-expressedbytheompiler as aset ofin-
stanedelarations,oneforeahgenerirepresentationtype.
Onemightask: whynotgettheprogrammertowritethese
instanedelarationsdiretly?
Our answeris stylistirather thantehnial. We want
to present generiprogramming inHaskellas ariher lan-
guage inwhihto writedefault method delarations, and
satteringthemoverseveralinstanedelarationsdoesnot
onveythatmessage. Thequestionaboutwhetherageneri-
defaultdelarationwasavailabletousewouldbeomemore
diuse,beausesomeparts,butnotothers,mightbeavail-
able. Writing thedelaration all atone, inthe lassde-
laration, seemsto bethesimplestandmostdiretthingto
do,eventhoughitdoesinvolvealittle newsyntax.
Another stylisti reason for our deision is that it is
rathereasyto onfusethe generiinstanedelarationfor,
say,produtsabwith\ordinary"instanedelarationsfor
the orresponding \ordinary"produttype (a;b). For ex-
ample,intheaseofShow,theordinaryinstanedelaration
forprodutsmightlooklikethis:
instane(Showa;Showb))Show(a;b)where
showsPre d(x;y)
="("++showsPre0x++","++showsPre0y++")" :
Beausetuplesaretypiallyshownusingdistxnotation,we
hoosetoover-ridethegeneridenition. Nevertheless,the
lassdelarationforShow willhavegivenrisetothegeneri
instanedelaration
instane(Show a;Showb))Show (ab)where
showsPred(x::y)
=showsPredx ++" "++showsPre dy:
Reall that produts ab are usedto represent theargu-
mentsofaonstrutor. Consequently,thegeneri instane
delaration speies the layout of onstrutor arguments:
theyareshownonseutivelyseparatedbyspaes.
4.4 Inferring instaneontexts
Whenalasshasgenerimethods,oneangiveaninstane
delarationwithoutprovidingtheodeforanyofthemeth-
ods. Butonestillhastoprovidetheontext fortheinstane
delaration. Forexample,oneouldnotwrite
instaneEq(List a)
(Eqa)onstraint. Insteadonemustwrite
instaneEqa)Eq(List a):
Inontrast,theexistingderivingmehanisminfersthene-
essaryinstaneontext. Theobviousquestionis: ouldthe
ompilerinfertheinstaneontextinournewsheme? For
example,wemightwrite
instane(::: ))Eq(List a)
indiatingthattheompilershouldllinthemissingontext
\(:::)". Indeed, wemightwant toallowsuhanabbrevia-
tioninany typesignature,allowing onetowrite,say,
f ::(::: ))a!a:
Theability to writesuhpartialtypesignatures, withthe
ellipsis lled in by type inferene, has been disussed on
the Haskell mailing list, and looks perfetly feasible from
atehnial standpoint. For instanedelarationsmatters
arestillfeasible,(albeitalittletrikier,involvingaxpoint
iteration)forrst-orderkindedtypes,butwebelievethatit
isinfeasibleforhigher-orderkindedtypes(seeSetion7.3).
Inanyase,thisissueisentirelyseparatefromourmain
theme,sowedonotdisussitfurther.
5 Mappingfuntions
Wehavenowpresentedthedesignasseenbytheprogram-
mer. Before we andesribe theimplementation,however,
weneedtopausetointroduebidiretionalmaps,whihare
anessentialfoundationtotheimplementation.
ReallfromSetion3.5ourgeneralplanforllinginthe
generimethodofaninstanedelaration. Supposewehave
thefollowinglassdelaration:
lassC awhere
op :: Opa:
Wewilldealonlywithsingle-parametertypelasses,butsee
Setion9. Wealso assume,for notational larity, thatthe
typeofmethodopisgivensimplybyOpa. Weanalways
introdueatypesynonymto make this so 2
. Nowsuppose
thattheprogrammerwritestheinstanedelaration
instanetx )C (T a):
wheretx isaontext,andaisasequeneoftypevariables.
Howisthe ompiler toll inthedenitionof methodop?
Following Setion3.5itanllinthus:
instanetx )C (T a) where
op = adapt-Op(op::Op(T Æ
a)):
That is, we all op at type T Æ
a, to produe a value of
type Op(T Æ
a), andthen onvertthe value toOp (T a).
The funtion adapt-Op does this impedane-mathing by
onvertingafuntionthatworksonvaluesoftypeT Æ
a to
onethatworksonT a.
adapt-Op :: 8a:Op(T Æ
a)!Op(T a)
2
Tehnially,Haskelltypesynonymsarenotpowerfulenoughto
dosuhanabbreviationforamethodlikeproperFration:
lassRealFraawhere
properFration :: (Integralb))a!(b;a):
sineitstypehasaontextatthebeginning. Butwewillpretend
thatsuhanabbreviationispossible.
thetypeofthemethod.Herearesomeexamples:
typeIna = a!String
adapt-In :: 8a:In(T Æ
a)!In(T a)
adapt-In = f !f from-T
typeOuta = String !a
adapt-Out :: 8a:Out(T Æ
a)!Out(T a)
adapt-Out = f !to-Tf
typeBotha = a!a
adapt-Both :: 8a:Both(T Æ
a)!Both (Ta)
adapt-Both = f !to-Tf from-T:
These adapt funtionsuse the funtionsto-T and from-T,
thatonvertbetweenTaandT Æ
a;theywereintroduedin
Setion3.3. Notiethatbothto-T andfrom-T are needed;
oneby itselfwillnotdo. Furthermore,whilewedene the
lass,andhenetheOptypes,one,wemaywriteinstanes
of that lass at many dierent types, T. So we want to
abstratouttheto-T andfrom-T funtionsfromtheadapt
funtions(notethata Æ
isatypevariablebelow):
adapt-Both 0
:: 8aa Æ
:(a Æ
!a)!(a!a Æ
)
!(Botha Æ
!Botha)
adapt-Both 0
tofrom = f !tof from
adapt-Both = adapt-Both 0
to-T from-T
It turns outto be onvenient to pakage up the to-T and
from-T funtionsintoanembedding-projetionpair:
dataEPaa Æ
= EPfto::a Æ
!a;from::a!a Æ
g:
HereEP a a Æ
isjustapairof funtions,onetoonvertin
onediretionandonetoonvertbak. Nowweanwrite
adapt-Both 00
:: 8aa Æ
:EPa a Æ
!(Botha Æ
!Botha)
adapt-Both 00
ep-a = f !toep-af from ep-a
onv-T :: 8a:EP(T a) (T Æ
a)
onv-T = EPfto=to-T;from=from-Tg
adapt-Both = adapt-Both 00
onv-T:
Thelaststepistomaketheadapt funtionitselfreturnan
embedding-projetionpair, ratherthanjustthe\to" fun-
tion; and at this stage we adopt the name bimap | for
\bidiretionalmapping":
bimap-Both :: 8aa Æ
:EPaa Æ
!EP(Botha)(Botha Æ
)
bimap-Bothep-a
= EPfto=f !fromep-af toep-a;
from=f !toep-af fromep-ag
adapt-Both = to(bimap-Bothonv-T):
Itis notatall obviouswhyweonstrutmappingsinboth
diretions,onlytodisardoneofthemwhenweuseit,but
it turns out to be essential when onstruting bimap for
arbitrarytypes,aswewillseeinthenextsetion.
5.1 Generating bidiretional mappingfuntions
Inthelastsetionwegeneratedbimap-Bothforapartiular
method type Both a. We also observed that appropriate
odedepends onthe struture ofthe type ofthe method,
so the million-dollar question is: how do we generate the
bidiretional mapsfor arbitrary methodtypes? We do it
simplybyindutionoverthetypeofthemethod,thus:
bimap-Op :: 8aa Æ
:EPaa Æ
!EP(Opa)(Opa Æ
)
bimap-Opep-a = bimapfOpag[a:=ep-a℄:
thought of as a meta-funtion, evaluated at ompile time,
thatreturnsaHaskellexpression. It takesasarguments: a
type(writteninurlybraes),andanenvironment%map-
pingtypevariables toexpressions. Thesyntax[a:=ep-a℄
meansanenvironmentthatbindsatoep-a.
We denebimap by indutiononthe strutureof type
expressions:
bimapfag% = %(a)
bimapf(!)g% = bimap-Arrow
bimapfTg% = bimap-T
bimapftug% = (bimapftg%)(bimapfug%)
where
bimap-Arrow :: 8aa Æ
bb Æ
:EPaa Æ
!EPbb Æ
!EP(a !b)(a Æ
!b Æ
)
bimap-Arrow ep-aep-b
= EPfto=f !toep-bf from ep-a;
from=f !fromep-bf toep-ag:
ThebimapfTgasedealswithtypeonstrutorsotherthan
(!),whihwedisussinSetion5.2. Letustakeanexam-
ple. ReallourBoth type:
typeBoth a = a!a:
Setting%=[a:=ep-a℄wehave
bimap-Bothep-a
= bimapfa!ag%
= (bimapf(!)ag%)(bimapfag%)
= ((bimap(!)%)(bimapfag%))(bimapfag%)
= bimap-Arrow ep-aep-a
= EPfto=f !toep-af fromep-ag;
from=f !fromep-af toep-a:
5.2 Mappingoverdata types
Whatifthereis adatatype involved? For exampleinthe
typeofreadBin,thereisapairintheresulttype:
typeReadBina = Bin!(a;Bin):
Ifwejusttryoururrentshemewegetstuk:
bimap-ReadBinep
= bimapfBin!(a;Bin)g%
= bimap-Arrow (bimapfBing%)(bimapf(a;Bin)g%):
Now,sineBinisnotaparameterisedtype,thereisnothing
todo,
bimap-Bin :: EPBinBin
bimap-Bin = id-EP
id-EP :: 8a:EPaa
id-EP = EPfto=x !x;from=x !xg
whereaspairsareparameterisedovertwotypes,sowemust
pushthemappingfuntionsinside:
bimap-Pair :: 8aa Æ
bb Æ
:EPaa Æ
!EPbb Æ
!EP(a;b)(a Æ
;b Æ
)
bimap-Pair ep-aep-b
= EPfto=(x Æ
;y Æ
)!(toep-ax Æ
;toep-by Æ
);
from=(x;y)!(fromep-ax;fromep-by)g:
tureofdatatypedelarations. Themappingfuntionforthe
datatype
dataTa
1 ::: a
k
= K
1 t
11 ::: t
1m1
jjK
n t
n1 ::: t
nmn
is givenbybimap-T displayedinFig. 1. Now,whatis the
type of this bidiretional map? The answeris simpleyet
mind-boggling: thetypeofbimap-T dependsonthekindof
T. Assumethat T haskind?as, for instane,Bin. Then
thebidiretionalmapsimplyhastypeEPTT(and,infat,
bimap-T =id-EP). If T has kind ? ! ?as all the Op's
have,thenbimap-T'stypeislose tothatofan\ordinary"
mappingfuntion:
bimap-T :: 8aa Æ
:EPaa Æ
!EP(T a)(Ta Æ
):
Amoreinvolvedkind,say(?!?)!(?!?),givesriseto
amoreompliatedtype:
bimap-T :: 8f f Æ
:(8bb Æ
:EPbb Æ
!EP(f b)(f Æ
b Æ
))
!(8aa Æ
:EPaa Æ
!EP(T f a)(T f Æ
a Æ
)):
Now bimap-T has a so-alled rank-2 type signature [12 ℄.
Roughlyspeaking,bimap-Ttakesbidiretionalmapstobidi-
retional maps(this iswhy thearguments ofbimap-T are
alledbimap-ai). Ingeneral,ifT haskind,thenbimap-T
hastypeBimapfgT T whereBimap is denedbyindu-
tiononthestrutureofkinds:
Bimapf?gt t Æ
= EPtt Æ
Bimapf1 !2gtt Æ
= 8aa Æ
:Bimapf1gaa Æ
!Bimapf2g(ta)(t Æ
a Æ
):
Ifhasordern,thenBimapfgisarank-ntype. Thisposes
noproblems,however, sinetheGlasgowHaskellCompiler
internallyusesavariantofthepolymorphi-alulus[17 ℄.
Wewill sayabitmoreabouthigher-orderkindedtypes
inSetion7. Forfurtherinformationonkind-indexedtypes
suhasBimap thereaderifreferredto[7 ℄.
6 Implementing generidefault methods
Now,atlast,wearereadytotakletheimplementation. We
desribe it as a Haskell soure-to-soure translation, per-
formed (at least notionally) prior totype heking. Why?
Thetypehekeralreadydoesalotofwhatwerequire.Also
weprobablyhaveabetterhanethatgeneridefaultmeth-
ods will worksmoothlywith ompliations suhas multi-
parameter type lasses [16 ℄, impliit parameters [13℄, and
funtionaldependenies[11 ℄.
The soure-to-soure translation goes as follows. For
eahdatatype delaration, T,wegeneratethefollowing:
2 ForeahonstrutorK avalueon-K oftypeConDesr
that desribes the properties of the onstrutor (Se-
tion6.1).
2 Atypesynonym,T Æ
,forT'sgenerirepresentationtype
(Setion6.2).
2 An embedding-projetion pair onv-T ::
8a:EP (T a) (T Æ
a), that onverts between T
anditsgenerirepresentationT Æ
(Setion6.3).
Foreahlassdelaration,for lassC,wegeneratethefol-
lowing (seeSetion6.4):
2 AnemaiatedlassdelarationforC,generatedsimply
byomittingthegenerially-denedmethods.
k
where
to-T (K1x11 ::: x1m
1
) = K1(to(bimapft11g%)x11) ::: (to(bimapft1m
1 g%)x1m
1 )
:::
to-T (Knxn1 ::: xnm
n
) = Kn(to(bimapftn1g%)xn1) ::: (to(bimapftnm
n g%)xnm
n )
from-T(K1x11 ::: x1m
1
) = K1(from(bimapft11g%)x11) ::: (from(bimapft1m
1 g%)x1m
1 )
:::
from-T(Knxn1 ::: xnm
n
) = Kn(from(bimapftn1g%)xn1) ::: (from (bimapftnm
n g%)xnm
n )
% = [a1:=bimap-a1;:::;ak:=bimap-ak℄
Figure1:ThebidiretionalmappingfuntionforthedatatypeT.
2 Foreahgenerimethodop::Opa inthelassdelara-
tion,abidiretionalmapbimap-Op::8aa Æ
:EPaa Æ
!
EP(Opa)(Opa Æ
)(seeSetion5).
2 Instanedelarations forC 1,C (a+b),C (ab)and
C ( of a), all obtained by seleting the eponymous
equations from the original lass delaration (see Se-
tion3.4).
Foreahinstanedelarationwegenerate(seeSetion6.5):
2 An extended instane delaration, obtained by adding
denitionsforthegenerimethodsthatarenotspeied
expliitlyintheinstanedelaration.
6.1 Construtors
Foreahonstrutor,K,inadatatypedelaration,wepro-
dueavalueoftypeConDesr thatgivesinformationabout
theonstrutor(infat,thetypeConDesrusedintheom-
pilerisslightlymoreelaborate):
dataConDesr = ConDesrfname::String;
arity::Int;
xity::Fixityg:
Asanexample,fortheList datatypewegenerate:
on-Cons;on-Nil :: ConDesr
on-Cons = ConDesr"Cons"2NoFixity
on-Nil = ConDesr"Nil"0NoFixity:
6.2 Generirepresentation types
Foreahdatatype,T,weprodueatypesynonymT Æ
,for
itsgeneri representation type. For example, for the data
type
dataLista = Cons a(Lista)jNil
wegeneratetherepresentationtype
typeList Æ
a = on-Consof(aLista)+on-Nilof1:
Ourgenerirepresentationtypeonstrutorsare justunit,
sum,produt,and \of". Inpartiular,thereisnoreur-
sion operator. Thus, we observe that List Æ
is just a non-
reursive type synonym: List (not List Æ
) appears on the
right-handside. SoList Æ
isnotareursive type;rather,it
expressesjustthetop\layer"ofaliststruture,leavingthe
original List to do the rest. But as we have seen, this is
enough: areursivefuntionjustdoesone\layer"ofreur-
sionatatime.
Thisisunusualomparedtootherapproahes. InPolyP
[8 ℄,forinstane,thereisanadditionaltypepatternfortype
reursion (at kind ? ! ?). A very signiant advantage
hereisthatthereisnoproblemwithmutually-reursivedata
types,nor withdatatypeswithmanyparameters,bothof
whih make expliit reursionoperators extremely lumsy
andhardtouseinpratie.
Our design makes do with just binary sum and prod-
ut. Algebraidata typeswithmanyonstrutors,eahof
whih has manyelds, are enoded as nestedusesof sum
andprodut. Theexatwayinwhihthenestingisdoneis
unimportanttoourmethod.Forexample:
dataColor = Red jBluejGreen
typeColor Æ
= on-Red of1
+ (on-Blueof1+on-Greenof1)
dataTreeab = Leaf ajNode(Tree ab)b(Treeab)
typeTree Æ
ab = on-Leaf ofa
+ on-Nodeof (Tree ab(bTreeab)):
OnemaywonderabouttheeÆienyoftranslatingauser-
dened data type into a generi formbefore operating on
it,espeiallyifeverythingisenodedwithonlybinarysums
andproduts. However,suÆientlyvigorousinliningmeans
thatthegeneridatarepresentationsneverexistatrun-time
(see Setion 6.6). But, in fat, we might want to explore
spae-timetrade-os, bygetting muhmore ompatode
in exhange for some datatranslation. Our designallows
thistrade-otobemadeonaase-by-asebasis.
Whether the enoding into sums and produts is done
in alinear or binary-sub-division fashion may or may not
aeteÆieny,dependingonhowvigoroustheinliningis.
6.3 Embedding-projetion pairs
ForeahdatatypeT,wealsogeneratefuntionstoonvert
between T and T Æ
. We saw the onversion funtions for
List inSetion3.3. Theproessisentirelystraightforward,
drivenbytheenoding. Forexample:
from-Color :: Color !Color Æ
from-ColorRed = Inl(Conon-Red Unit)
from-ColorBlue = Inr (Inl(Conon-BlueUnit))
from-ColorGreen = Inr (Inr(Conon-GreenUnit))
to-Color::Color Æ
!Color
to-Color(Inl(Con on-RedUnit)) = Red
to-Color(Inr (Inl(Conon-BlueUnit))) = Blue
to-Color(Inr (Inr(Conon-GreenUnit))) = Green:
Forbimapwehavetopakagethetwoonversionfuntions
intoasinglevalue:
onv-List :: 8a:EP(List a)(List Æ
a)
onv-List = EPfto=to-List;from=from-Listg
onv-Color :: EPColorColor Æ
onv-Color = EPfto=to-Color;from =from-Colorg:
For eah generi method op ::Op a ontained in a lass
delarationwegenerateabidiretionalmap
bimap-Op :: 8aa Æ
:EPaa Æ
!EP(Opa)(Opa Æ
)
thatallowsustoonvertbetweentypesandrepresentation
types(thedenitionofbimap-Op isgiveninSetion5).
Furthermore,weprodueinstanedelarations
instaneC 1
instane(C a;C b))C (a+b)
instane(C a;C b))C (ab)
instane(C a))C (ofa)
whosebodiesare lled withthe generi methods fromthe
originallassdelaration(seeSetion3.4). Ifanequationfor
atypepatternismissing, themethodoftheorresponding
instane is undened. There is, however, one important
exeptionto this rule: ifnoequationis givenfor the type
patternofaas,forexample,inthelassesEqandBinary,
we dene the generi methods of the C ( of a) instane
by:
opfofag = to(bimap-Op(on-EP))(op::Opa)
whereon-EPisgivenbythefollowingpseudo-Haskellode
(whihdenesafamilyoffuntions):
on-EP :: 8a:EPa(ofa)
on-EP = EPfto=x !Conx;
from=(Conx)!xg:
Again,weemploythebidiretionalmaptoonvertbetween
twoisomorphitypes.
6.5 Translatinginstanedelarations
AninstanedelarationfortypeT isextendedbyllingin
implementations for themethods. More speially, ifthe
methodopisnotspeiedandifitenjoysageneridefault
denition,thenthefollowing equationissupplemented:
op = to(bimap-Oponv-T)(op::OpT Æ
):
That'sit.
6.6 Inlining
It does not sound very eÆient to translate a value from
TatoT Æ
a andthentooperateonit,butwebelievethat
abitofjudiiousinlininganyieldmoreorlesstheodeone
wouldhavewrittenbyhand. Letusonsider,for example,
showBin at type List. TheshowBinList methodwill look
somethinglikethis:
showBinList :: (Binarya))Lista!Bin
showBinListxs = showBin(from-Listxs)
typeList Æ
a = (aLista)+1
from-List :: Lista!List Æ
a:
Theallto showBin isat typeList Æ
a,so the overloading
anberesolvedstatially. Assumingthatthemethodbodies
(giveninSetion3.1)areinlined, weget:
showBinListxs
= asefrom-Listxsof
Inlz !0:asezof
(x::y)!showBinx++showBiny
Inrz!1:asezofUnit![℄:
reursivedenition:
from-List(Consx xs) = Inl(x::xs)
from-ListNil = InrUnit:
IfweinlinethisdenitioninshowBinListandsimplifyusing
standardtransformations,weget
showBinListxs
= asexsof
Consx y!0:showBinx++showBiny
Nil!1:[℄;
whihisaboutasgoodasweanhopefor.
7 Higher-order kindedtypes
Funtional programmers love abstration. In Haskell we
an,for instane,abstratovertheList datatypein
dataRosea = Branha (List(Rosea))
toobtainthemoregeneraltype:
dataGRosef a = GBranh a(f (GRosef a)):
Here, the type variable\f"ranges overtype onstrutors,
rather than types. Formally, GRose has kind(? ! ?) !
?! ?. There are numerousexamplesof suhtypedeni-
tionsin[14 ,5 ℄.Alas,itisimpossibletodenemanyinstane
delarationsfor GRose inHaskellatall. Inthis setionwe
desribe theproblem and asolution. This setion is quite
independent of the rest of the paper. Thoughwe beame
aware of the issue whenworkingongeneri programming,
we propose an extensionto Haskell that is ompletely or-
thogonaltogeneriprogramming.
7.1 What's theproblem?
Consider rstdeninganinstane for Binary (Rose a)by
hand|weignorereadBinhere:
instane(Binarya))Binary (Rosea)where
showBin(Branhx ts) = showBinx++showBints:
TherstalltoshowBinontherighthandsiderequiresthat
Binary a should hold; theontext,(Binary a), takesare
ofthat. TheseondallisattypeList(Rosea). Assuming
wehaveaninstaneelsewhereoftheform
instane(Binaryt))Binary(List t)
the seond all requires Binary (Rose a), and there is an
instanedelarationforthattoo|itgivesrisetoareursive
alltoshowBin.
Butmattersarenotsosimplewhenwewanttowritean
instaneBinary(GRosef a). Wemighttry
instane(??? ))Binary(GRosef a)where
showBin(GBranhx ts) = showBinx++showBints:
The ontext (??? ) mustaount for the alls to showBin
on the right-hand side. The rst one is ne: it requires
Binary a as before. Butthelatterisbadnews: itrequires
Binary (f (GRosef a)),andweertainlyannotwrite
instane(Binarya;Binary(f (GRosef a)))
)Binary(GRosef a)where
showBin(GBranhx ts) = showBinx++showBints:
ThisisnotlegalHaskelland,evenifitwere,thetypeheker
woulddiverge. Indeed,noordinaryHaskellontextwilldo.
What we need is a way to simplify the prediate
f (GRosef a). Thetrikistotakethe\onstant"instane
delarationthatweassumedforBinary(List a)above,and
abstratoverit:
instane(Binarya;8b:(Binaryb))Binary(f b))
)Binary(GRosef a)where
showBin(GBranh xts) = showBinx++showBints:
Now, as well as (Binary a), the ontext also ontains
a polymorphi prediate. This prediate an be used to
redue the prediate Binary (f (GRose f a)) to just
Binary (GRose f a), and we have aninstanedelaration
forthat.
Viewedin operational terms, the prediate (Binary a)
ina ontext orresponds to passing a ditionary for lass
Binary. A prediate 8b:Binary b )Binary (f b) orre-
spondstopassingaditionarytransformer tothefuntion.
7.3 Derivinginstanedelarations
Ofourse, sineBinary isaderivablelassbyvirtueofthe
generi defaultdenitions, we neednot dene showBin at
all. Weansimplywrite
instane(Binarya;8b:(Binaryb))Binary (f b))
)Binary(GRosef a)
andgetjustthesameeetasbefore. Inotherwords,thede-
rivingmehanismworkshappilyfortypesofarbitrarykinds.
Hereisaplaewhereaprogrammer-writtenontextfor
theinstanedelarationisessential. Weouldnotusethe
ideaofSetion4.4towrite:
instane(::: ))Binary (GRosef a):
Theproblemisthatthereisno\mostgeneralinstanede-
laration". Toillustratethe pointonsider thefollowing in-
stanedelarationfor theabstrattypeSet:
instane(Binarya;Orda))Binary(Set a):
Notethat we additionallyrequire that a is aninstane of
Ord. Now,giventheinstanedelarationforGRose above,
weannotinferBinary (GRose SetInt)sineSet doesnot
satisfy8b:(Binaryb))Binary (Setb). Ifwerequiresuh
aninstane,wemustgeneralizetheGRose instane:
instane(Binarya;8b:(Binaryb;Ord b))Binary(f b))
)Binary(GRosef a):
Byadding further lassonstraints to f's ontext, we an
generalize the instane delarationevenmore. Sadly, this
implies that there is no \most general" instane whih
derivingouldinfer. Notethatthisproblemdoesnotrop
upforrst-orderkindedtypes.
7.4 Formalising theextension
Hereisthegrammarforgeneralizedinstanedelarations:
instanehead ::= instane(tx
1
;:::;tx
n ))C t
ontext tx ::= 8a:(tx
1
;:::;tx
n
))Ct:
Aontextoftheform8a:(tx1;:::;txn))C twithn>1
is alled apolymorphi prediate. Notethat for n =0 we
have\ordinary"Haskell98prediates.
tions
How dowe translate amethodallop::Op T? Wemust
reateaC-ditionaryforT ifopisamethodoflassC. In
thehigher-orderkindedsituation,wemayneedtoreatea
ditionarytransformer to passto op. Fortunately,itturns
outthatthenow-standardmahineryto onstruttheor-
retditionary topassaneasily beextendedto onstrut
ditionarytransformerstoo.
Ataallsitewehavetosolvethefollowingproblem: we
haveasetofassumptionsH andasinglelauseH,theditio-
nary(transformer)required,andwewanttoknowwhether
H is alogialonsequene ofH. Additionallywereturnan
expression for theditionary (transformer) for H. We use
the following notation: H `H 7!d meansthatd is adi-
tionary (transformer)expressionthatshowshowH anbe
deduedfromH.
TheassumptionsH embody:
2 Anyinstanedelarationsinsope. Forexample:
EqInt7!dit-Eq-Int
8a:Eqa)Eq(Lista)7!dit-Eq-List .
2 Information aboutsuperlasses. Forexample:
8a:Orda)Eqa7!dit-Eq-Ord:
ThissaysthatifwehaveOrd a weandedueEqa;in
onretetermswewitnessthisfatbytheseletorfun-
tion dit-Eq-Ord whih selets the Eq ditionary from
theOrd one.
2 Constraintsfromthetypesignature. Forexample,ifwe
arehekingtypesforthefuntion
f ::
H )T
f x = :::
then we putthe assumptions
H inourassumptionset,
andtrytodeduealltheditionariesthatareneededby
allsinthebodyoff.
Weuse the following inferene rules (A standsfor As-
sumption,CforConjuntion,MPforModusPonens):
(H 7!d)2H
H `H 7!d
(A)
H `H
1 7!d
1
H `H
n 7!d
n
H `(H
1
;:::;H
n )7!(d
1
;:::;d
n )
(C)
H `(8a:
H )Q)7!f H `
H%7!d
H `P7!(f d)
(MP)
where%=[a:=x℄isarenamingsubstitution(thexiarefresh
variables) and =math(Q%;P)is the resultofmathing
Q%againstP(notethatonlythevariablesinQ%arebound).
Sofar,theserulesareentirelystandard,see,forinstane,
[10 ℄. Totheseweaddonenewrule(DRstandsforDedu-
tionRule).
H;(
H%7!v)`Q%7!d
H `(8a:
H )Q)7!(v !d)
(DR)
where % = [a:=℄ is a Skolem substitution, that is, the
i are Skolemonstants. Thus,to deduethe polymorphi
prediate 8a:
H ) Q we add the body
H to the set of
ensuresthatthisderivationworksfor alla.
Thenewruleisalled Dedution Rulebeause itre-
semblesthededutiontheoremofrst-orderlogi. Itisalso
reminisentoftheusualtyping rulefor-abstrationwhile
ModusPonensorrespondstothetypingruleforapplia-
tion.Infat,thesetworulesaptureditionaryabstration
andditionaryappliation.
Here is an example of a dedution using these rules.
Later lines are dedued from earlier ones using the spei-
edrule(weabbreviateBinary byB andOrd by0).
H = fOrdInt7!d-O-I;
Binary Int7!d-B-I;
(8a:(Binarya;Orda)
)Binary(Seta))7!d-B-Sg
(4)H `0Int7!d-O-I A
(3)H `BInt7!d-B-I A
(2)H `(B Int;0Int)7!(d-B-I;d-O-I) C(3,4)
(1)H `(8a:(Ba;0a))B(Set a))7!d-B-S A
(0)H `B(Set Int)7!d-B-S(d-B-I;d-O-I) MP(1,2)
Hereisanotherexample,thistimeofahigher-orderase:
H = fBinaryInt7!d-B-I;
(8a:(Binarya))Binary (Lista))7!d-B-L;
(8f a:(Binarya;8b:(Binaryb))Binary(f b))
)Binary(GRosef a))7!d-B-Gg:
WeabbreviateH;(Binary7!v)byH 0
.
(9)H 0
`(8b:(B b))B(Listb))7!d-B-L A
(8)H 0
`B7!v A
(7)H 0
`(B;8b:(Bb))B(List b))
7!(v;d-B-L) C(8,9)
(6)H 0
`(8f a:(::: ))B(GRosef a))7!d-B-G A
(5)H 0
`B(GRoseList)7!d-B-G (v;d-B-L) MP(6,7)
(4)H `(8b:(Bb))B(GRoseListb))
7!(v!d-B-G (v;d-B-L)) DR(5)
(3)H `BInt7!d-B-I A
(2)H `(BInt;8b:(B b))B(GRoseListb))
7!(d-B-I;v !d-B-G(v;d-B-L)) C(3,4)
(1)H `(8f a:(:::))B(GRosef a))7!d-B-G A
(0)H `B(GRose(GRoseList)Int)
7!d-B-G(d-B-I;v !d-B-G(v;d-B-L))MP(1,2)
Thenewinferenerulekiksinatline(4)andintroduesa
newassumption,B7!v,thatisusedinline(8).
8 Relatedwork
This paper improveson our earlier work[4 ℄ inseveral re-
spets. First,generidenitionsnowappear solelyinlass
delarations as generi default methods. In the previous
design generi denitions and lasses were two ompeting
features. We feel that the new proposal ts better with
\the spirit of Haskell". Seond, we have spelled out the
implementation in onsiderable detail. In partiular, the
notion of generi representation typesand the onversion
betweentypesandrepresentationtypeshasbeenmadepre-
ise. Third, we have desribed a separate extension that
allows the programmer to dene instane delarations for
higher-orderkindedtypes. Theneedforthisextensionwas
notedin[4 ℄butnosolutionwasgiven.
Thoughthereisaonsiderableamountofworkongeneri
programming[18 ,3,9 ℄this isthe rstpaperweare aware
of| apartfrom PolyP [8℄ |that aimsat addinggeneri
tension oers a speial onstrut (essentially, atype ase)
for deninggenerifuntions. Theresultingdenitionsare
similar to ours (modulo notation) exept that the generi
programmermustadditionallyonsiderasesfortypeom-
position andfor typereursion. Furthermore,PolyP is re-
strited to regular data types of kind?! ?, whereasour
proposalworksforalltypesofallkinds. Thisisquiteasig-
niantadvantage. Inpartiular,ourproposaldealsgrae-
fullywithmutually-reursivedatatypesandwithdatatypes
withmany parameters,bothof whihmakeexpliitreur-
sionoperatorslumsyandhardtouseinpratie.
The DrIFTtool [19℄isa pre-proessor for Haskell that
allows the programmer to speify rules that explain how
to implement aderivinglause for lasses otherthanthe
standard lasses. The rules are speiedas Haskell fun-
tions, mapping a type representation to Haskell program
text. DrIFThasthesigniantadvantageoftehnialsim-
pliity. However, our system oers muh stronger stati
guarantees: ifageneridefaultdelarationpassesthetype
heker,thensowillanyinstanedelarationsthatuseit. In
DrIFT,arulemaytypehekne, whileproduingHaskell
text that itself will not typehek. We also believe that
our loser integration with the language design(ahieving
generi programmingby enrihing default-methoddelara-
tions)maketheprogrammer'slifeeasier.
9 Conlusions and furtherwork
This paper desribes two separate extensions to Haskell.
Therst extensionsupports generiprogrammingthrough
anewformof defaultmethoddelaration. Theseondex-
tensionallowsonetodeneinstanedelarationsforhigher-
orderkindedtypesthroughthenotionofpolymorphipredi-
ates. Thoughtheseextensionsareorthogonaltoeahother,
the seond ensures that onegets the most outof the rst
one (surely,one wants to derive instanesfor higher-order
kindedtypes).
WebelievethatourproposalstnielyintotheHaskell
language:
2 They t with the \spirit of Haskell". At rst sight,
generiprogrammingandHaskelltypelassesareinom-
petition, butwe use generi programmingto smoothly
extendthepoweroftypelasses.
2 Weareabletoexplainwhat\deriving"meansinasys-
temati way. The ad ho nature of deriving has long
beenonsideredawart,andprogrammersoftenwantto
addnew\derivable"lasses|thatis,lassesforwhih
youansay\deriving(C)". Nowtheyan.
2 Generidenitionsanbeover-riddenatpartiulartypes
byprogrammer-suppliedinstanedelarations. Thissets
our approah apart from other generi programming
shemes. Notonlyis thisusefulforprimitivetypes,but
generimethodsareofteninappliableforabstrattypes
| onsider equality on sets represented as unordered
lists,forexample.
2 There is norun-time passingor ase-analysis of types,
beyondHaskell'sexistingditionarypassing. Ofourse,
ditionary-passingisasortoftypepassing,butitalready
exists inHaskell,anditwouldbeextremelytiresometo
introdueanother,overlappingmehanism.
Norarethereanynewrequirementstoinspetthe run-
timerepresentationofavalue,afeatureofsomepropos-
als. Our proposal is a 100% ompile-timetransforma-
tion.
bletoeliminaterun-timeoverhead(seeSetion6.6).
2 Our sheme deals suessfully with onstrutor names
and labels. Wehavetoadmit, though, thatthis is one
ofthetrikierornersofthedesign.
2 We unninglyre-use Haskell's type-lass mehanism to
instantiatethegeneri methodsfor partiulartypes, by
expressingthegeneri methodsasgeneri instanede-
larations (Setion 4.3). This approah means that we
do not need to explain or implement exatly how this
odeinstantiationtakesplae(e.g. howmuhisdoneat
ompiletime). Instead we justpiggy-bakon anexist-
ingpieeofimplementationtehnology. (Thisisreallya
pointabouttheimplementation,notaboutthedesign.)
There seem to be twomain shortomings. Firstly, the
detailsofimplementingthegeneridefaultmethods(repre-
sentationtypes,bidiretionalmappingfuntions,andsoon)
areundeniablysubtle,whihisoften abadsign. Seondly,
thetehnologytodealwithonstrutorandeldlabelsdoes
nottinaselegantlyaswewouldwish.
Weareurrentlyimplementingtheproposalandwehope
tomakethenewfeaturesavailableinthenextreleaseofthe
GlasgowHaskellCompiler.
There are several diretions we plan to explore in the
future:
2 Currently,generidefaultdelarationsmaybegivenonly
fortypelasses. However,thetheory[6 ℄alsodealswith
onstrutor lasses whose type parameter range over
types ofrst-order kind. Consequently, we plan to lift
thisrestrition.
2 InHaskell98instaneheadsmusthavethegeneralform
C (T a) where a is a sequene of distint variables.
TheGlasgowHaskellCompiler,however,allowsfornon-
general instaneheads suhas C (List Char). We are
ondent that the implementation sheme for generi
methodsanbeextendedtodealwiththisextraompli-
ation.
2 Multi-parametertypelassesareonthewishlistofmany
Haskell programmers. So it would be a shame if the
generi extension failed to supportthem. Now, multi-
parameterlassesorrespondtogeneridenitionswith
multipletypearguments,whiharetheoretiallywellun-
derstood. Soweareondentthatweanalsodealwith
thisgeneralization.
Aknowledgements
Wewouldliketothankthreeanonymousrefereesformany
valuableomments. ThanksarefurthermoreduetoJeremy
GibbonsfortheHaskellequalssign.
Referenes
[1℄ RolandBakhouse,PatrikJansson,JohanJeuring,and
LambertMeertens.GeneriProgramming|AnIntro-
dution. InS.DoaitseSwierstra,PedroR.Henriques,
andJoseN.Oliveira,editors,3rdInternationalSummer
Shool on Advaned Funtional Programming, Braga,
Portugal, volume 1608 of Leture Notes in Computer
Siene,pages28{115.Springer-Verlag,Berlin, 1999.
[2℄ Rihard Bird, Oege de Moor, and Paul Hoogendijk.
Generi funtional programmingwith typesand rela-
tions. Journalof Funtional Programming,6(1):1{28,
January1996.
YellowSeriesReport92/480/18, Department ofCom-
puterSiene,UniversityofCalgary,June1992.
[4℄ Ralf Hinze. A generi programming extension for
Haskell. InErikMeijer, editor,Proeedings ofthe 3rd
HaskellWorkshop,Paris,Frane,September1999.The
proeedingsappearedas a tehnial reportof Univer-
siteitUtreht,UU-CS-1999-28.
[5℄ RalfHinze.Manufaturingdatatypes.JournalofFun-
tional Programming, Speial Issue onAlgorithmi As-
pets ofFuntionalProgramming Languages, 2001. To
appear.
[6℄ RalfHinze. Anewapproahtogenerifuntionalpro-
gramming. InThomasW.Reps,editor,Proeedings of
the27thAnnualACMSIGPLAN-SIGACTSymposium
onPriniplesofProgrammingLanguages(POPL'00),
Boston,Massahusetts,pages119{132,January2000.
[7℄ RalfHinze. Polytypivaluespossesspolykindedtypes.
In RolandBakhouse and J.N.Oliveira, editors, Pro-
eedingsoftheFifthInternationalConfereneonMath-
ematis of Program Constrution (MPC 2000), July
2000.
[8℄ PatrikJanssonandJohanJeuring. PolyP|apolytypi
programminglanguageextension.InConfereneReord
24th ACM SIGPLAN-SIGACT Symposium on Prin-
iples of Programming Languages, POPL'97, Paris,
Frane, pages470{482.ACM-Press,January1997.
[9℄ C.B.Jay,G.Belle,andE.Moggi.FuntorialML.Jour-
nal ofFuntionalProgramming,8(6):573{619, Novem-
ber1998.
[10℄ MarkP.Jones. QualiedTypes: Theory andPratie.
CambridgeUniversityPress,1994.
[11℄ MarkP.Jones. Typelasseswithfuntionaldependen-
ies. InG.Smolka,editor,Proeedingsofthe9thEuro-
peanSymposiumonProgramming,ESOP2000,Berlin,
Germany, volume1782 of Leture Notes inComputer
Siene,pages230{244.Springer-Verlag,Marh2000.
[12℄ DanielLeivant. Polymorphi typeinferene. InPro.
10th Symposium on Priniples of Programming Lan-
guages,1983.
[13℄ Jerey R. Lewis, Mark B. Shields, Erik Meijer, and
JohnLaunhbury.Impliitparameters:Dynamisop-
ingwithstatitypes. InThomasW.Reps,editor,Pro-
eedingsof the27thAnnual ACMSIGPLAN-SIGACT
Symposium onPriniples of Programming Languages,
Boston,Massahusetts,pages108{118,January2000.
[14℄ Chris Okasaki. Purely Funtional Data Strutures.
CambridgeUniversityPress,1998.
[15℄ Simon Peyton Jones and John Hughes, edi-
tors. Haskell 98 | A Non-strit, Purely Fun-
tional Language, February 1999. Available from
http://www.haskell.org/defini tion /.
[16℄ Simon Peyton Jones, Mark Jones, and Erik Meijer.
Type lasses: Exploringthedesignspae. InProeed-
ingsoftheHaskellWorkshop,1997.
gramtransformation: A reportfrom thetrenhes. In
Hanne Riis Nielson, editor, Programming Languages
andSystems|ESOP'96, 6thEuropean Symposium on
Programming,Linkoping,Sweden,22{24April,volume
1058ofLeture NotesinComputerSiene, pages18{
44.Springer-Verlag,1996.
[18℄ KarlFritzRuehr. Analytial andStrutural Polymor-
phismExpressedusingPatternsoverTypes.PhDthesis,
UniversityofMihigan,1992.
[19℄ Noel Winstanley. A type-sensitive preproessor for
Haskell. InGlasgowWorkshoponFuntionalProgram-
ming,Ullapool,1997.