Table Of ContentHaskell’06
September 17, 2006 • Portland, Oregon, USA
Proceedings of the
ACM SIGPLAN
2006 Haskell
Workshop
k
o
o
H
s
e
m
a
J
y
b
o
t
o
h
P
r
e
v
o
C
Sponsored by the
Association for Computing Machinery
Special Interest Group on Programming Languages (SIGPLAN)
The Association for Computing Machinery
1515 Broadway
New York, New York 10036
Copyright © 2006 by the Association for Computing Machinery, Inc. (ACM). Permission to make digital
or hard copies of portions of this work for personal or classroom use is granted without fee provided that
copies are not made or distributed for profit or commercial advantage and that copies bear this notice and
the full citation on the first page. Copyright for components of this work owned by others than ACM must
be honored. Abstracting with credit is permitted. To copy otherwise, to republish, to post on servers or to
redistribute to lists, requires prior specific permission and/or a fee. Request permission to republish from:
Publications Dept., ACM, Inc. Fax +1 (212) 869-0481 or <permissions@acm.org>.
For other copying of articles that carry a code at the bottom of the first or last page, copying is permitted
provided that the per-copy fee indicated in the code is paid through the Copyright Clearance Center,
222 Rosewood Drive, Danvers, MA 01923.
Notice to Past Authors of ACM-Published Articles
ACM intends to create a complete electronic archive of all articles and/or other material previously
published by ACM. If you have written a work that has been previously published by ACM in any journal
or conference proceedings prior to 1978, or any SIG Newsletter at any time, and you do NOT want this
work to appear in the ACM Digital Library, please inform permissions@acm.org, stating the title of the
work, the author(s), and where and when published.
ISBN: 1-59593-489-8
Additional copies may be ordered prepaid from:
ACM Order Department
PO Box 11405
New York, NY 10286-1405
Phone: 1-800-342-6626
(US and Canada)
+1-212-626-0500
(all other countries)
Fax: +1-212-944-1318
E-mail: acmhelp@acm.org
ACM Order Number 565062
Printed in the USA
ii
Foreword
It is with great pleasure that I present to you the proceedings of the 10th ACM SIGPLAN Haskell
Workshop – Haskell’06. The purpose of the workshop is to discuss experience with Haskell and
possible future developments of the language. Topics of interest are all aspects of the design,
semantics, theory, application, implementation and teaching of Haskell. Since 1997, the Haskell
Workshop has been co-located with ICFP – the International Conference on Functional
Programming.
This year’s call for papers attracted 24 submissions of full papers. Each of the papers was reviewed
by at least 3 international reviewers. During a five-day electronic meeting, the Program Committee
selected 10 papers for publication in these proceedings and presentation at the workshop. In addition,
we accepted 3 demos and a status report on Haskell’ – the next revision of the Haskell language.
Also, the program includes the traditional discussion on the “Future of Haskell”.
Many people have helped to make the Haskell Workshop 2006 a reality. I would like to thank all the
authors of the submitted papers, the Program Committee and the 32 external reviewers. Since last
year, the Haskell Workshop has a Steering Committee that has proved to be an enormous help during
all phases of planning the workshop. The Steering Committee is also to thank for the fact that there is
now a permanent homepage for the Haskell Workshop. I am very grateful for the fruitful
collaboration with ICFP. Special thanks go to Matthias Blume and Patricia Johann, the ICFP
Workshop co-chairs, to John Reppy, the ICFP General Chair and to the ICFP local arrangements
team. Lisa Tolles (Sheridan Printing) and Adrienne Griscti (ACM) have helped with the preparation
of these printed proceedings. Finally, I would like to thank ACM SIGPLAN for sponsoring this
workshop once again.
I hope that you find the program interesting and that you enjoy the workshop!
Andres Löh
Program Chair
Universität Bonn, Germany
iii
Table of Contents
Haskell 2006 Workshop Organization...............................................................................................................vi
Session 1
Session Chair: A. Löh (Universität Bonn)
• RepLib: A Library for Derivable Type Classes........................................................................................................1
S. Weirich (University of Pennsylvania)
• A Generic Recursion Toolbox for Haskell—Or: Scrap Your Boilerplate Systematically.................................13
D. Ren, M. Erwig (Oregon State University)
• Strong Types for Relational Databases (Functional Pearl)....................................................................................25
A. Silva (CWI), J. Visser (Universidade do Minho)
Session 2
Session Chair: S. Peyton Jones (Microsoft Research)
• Polymorphic Variants in Haskell..............................................................................................................................37
K. Kagawa (Kagawa University)
• Extended Static Checking for Haskell......................................................................................................................48
D. N. Xu (University of Cambridge)
• Running the Manual: An Approach to High-Assurance Microkernel Development.........................................60
P. Derrin, K. Elphinstone, G. Klein, D. Cock, M. M. T. Chakravarty (University of New South Wales)
• Strongly Typed Memory Areas: Programming Systems-Level Data Structures
in a Functional Language..........................................................................................................................................72
I. S. Diatchki (Oregon Health & Science University), M. P. Jones (Portland State University)
Session 3
Session Chair: I. Jones (Galois Connections)
• User-Level Transactional Programming in Haskell...............................................................................................84
P. Thiemann (Universität Freiburg)
• An Extensible Dynamically-Typed Hierarchy of Exceptions................................................................................96
S. Marlow (Microsoft Research)
• Interactive Debugging with GHCi...........................................................................................................................107
D. Himmelstrup
• Introducting the Haskell Equational Reasoning Assistant...................................................................................108
A. Gill (Galois Connections)
Session 4
Session Chair: H. Nilsson (University of Nottingham)
• GenI: Natural language generation in Haskell......................................................................................................110
E. Kow (INRIA/LORIA/UHP)
• Statically Typed Linear Algebra in Haskell...........................................................................................................120
F. Eaton (University College London)
• Haskell’ Status Report: An Update on the Next Haskell Standard....................................................................122
I. Jones (Galois Connections)
Session 5 — Discussion on The Future of Haskell
Session Chair: G. Keller (University of New South Wales)
Author Index...............................................................................................................................................................123
v
Haskell Workshop 2006 Organization
Program Chair: Andres Löh (Universität Bonn, Germany)
Steering Committee: Manuel Chakravarty (University of New South Wales, Australia)
Johan Jeuring (Universiteit Utrecht, The Netherlands)
John Launchbury (Galois Connections, USA)
Daan Leijen (Microsoft, Redmond, USA)
Andres Löh (Universität Bonn, Germany)
Henrik Nilsson (Rutgers University, USA)
Simon Peyton Jones (Microsoft Research, UK)
Program Committee: Koen Claessen (Chalmers University of Technology, Sweden)
Bastiaan Heeren (Universiteit Utrecht, The Netherlands)
Paul Hudak (Yale University, USA)
Isaac Jones (Galois Connections, Portland, USA)
Gabriele Keller (University of New South Wales, Australia)
Oleg Kiselyov (FNMOC, USA)
Andres Löh (Universität Bonn, Germany)
Conor McBride (University of Nottingham, UK)
Shin-Cheng Mu (Academia Sinica, Taiwan)
Andrew Tolmach (Portland State University, USA)
Additional reviewers: Björn Bringert Dylan McNamee
Paul Callaghan Akimasa Morihata
Manuel Chakravarty Henrik Nilsson
Kung Chen Bruno Oliveira
Iavor S. Diatchki Lee Pike
Atze Dijkstra Alexey Rodriguez
Jeroen Fokker Sean Seefried
Andy Gill Chung-chieh Shan
Jurriaan Hage Paul Steckler
Makoto Hamana Don Stewart
Stefan Holdermans Jim Teisher
Zhenjiang Hu Tarmo Uustalu
Graham Hutton Meng Wang
Johan Jeuring Stephanie Weirich
Roman Leshchinskiy Peter White
Peter Ljunglöf Haiyan Zhao
Sponsor:
vi
RepLib: A Library for Derivable Type Classes
StephanieWeirich
UniversityofPennsylvania
sweirich@cis.upenn.edu
Abstract thesetypes.Furthermore,thereisoftenarelationshipbetweenthe
structureofadatatypedefinitionanditsinstanceforEq,somany
Some type class instances can be automatically derived from the
oftheseinstanceshavesimilardefinitions.Asaresult,theHaskell
structure of types. As a result, the Haskell language includes the
languageincludesthederivingmechanismthatcanbeusedtodi-
“deriving” mechanism to automatic generates such instances for
rectaHaskellcompilertoinsertaninstanceoftheEqbasedonthe
a small number of built-in type classes. In this paper, we present
structureofanewlydefineddatatype.Forexample,thecodeabove
RepLib, a GHC library that enables a similar mechanism for ar-
maybereplacedbythefollowing.
bitrary type classes. Users of RepLib can define the relationship
betweenthestructureofadatatypeandtheassociatedinstancedec-
dataTree a =Leaf a |Branch (Tree a)(Tree a)
larationbyanormalHaskellfunctionsthatpattern-matchesarepre-
deriving(Eq)
sentationtype.Furthermore,operationsdefinedinthismannerare
extensible—instancesforspecifictypesnotdefinedbytypestruc-
turemayalsobeincorporated.Finally,thislibraryalsosupportsthe DerivingisausefuladditiontotheHaskelllanguageinthatit
definitionofoperationsdefinedbyparameterizedtypes. cuts down on the boilerplate instance declarations that program-
mersmustwritewhentheydeclarenewdatatypes.Importantly,it
Categories and Subject Descriptors D.1.1 [Programming Tech- isanoptionalmechanism,providingadefaultinstanceforEqwhen
niques]:Applicative(Functional)Programming directed,butallowingprogrammerstowritetheirownspecialized
instancesforEq whennecessary.
GeneralTerms Design,Languages
Unfortunately,derivingonlyworksforahandfulofbuilt-intype
Keywords Type-indexed programming, Datatype-generic pro- classes.InHaskell98,onlyEq,Ord,Bounded,Show andRead
gramming,Representationtypes,GADT are derivable. User-defined type classes cannot take advantage of
deriving. To address this limitation, there have been a number of
1. Derivingtype-indexedoperations proposalsforexperimentallibrariesandextensionstoHaskell,such
asPolytypicProgramming(PolyP)[18],GenericHaskell[3,24],
Type-indexedfunctionsarethosewhosebehaviorisdeterminedby
Derivable type classes [11], the Typeable type class (with the
thetypesoftheirarguments.InHaskell,typeclasses[32,8]enable
“ScrapyourBoilerplateLibrary”[21,22,23]),preprocessorssuch
thedefinitionanduseofsuchfunctions.Forexample,theEq type
asDrIFT[6]andTemplateHaskell[30],andvariousencodingsof
classdefinesthesignatureofpolymorphicequality.
representation types [39, 5, 13]. These proposals each have their
classEq a where(≡)::a →a →Bool benefits,butnonehasemergedasaclearlybettersolution.
In this paper, we present the RepLib library for the Glasgow
TheinstancesoftheEq classdefinethebehaviorofpolymorphic
HaskellCompiler(GHC)[7]thatenablesaderiving-likebehavior
equalityatspecifictypes.Forexample,aninstanceforadatatype
forarbitrarytypeclasses.ItworksbyusingTemplateHaskelltode-
Treeisbelow.
finerepresentationtypesthatprogrammersmayusetospecifythe
dataTree a =Leaf a |Branch (Tree a)(Tree a) defaultbehavioroftype-indexedoperations.Representationtypes
reflectthestructureoftypesasHaskelldata,thereforeprogrammers
instanceEq a ⇒Eq (Tree a)where
candefinetype-indexedoperationsasordinaryHaskellfunctions.
(Leaf x1) ≡(Leaf x2) =x1 ≡x2
Theideaofprogrammingwithrepresentationtypesisitselfnot
(Branch t1 t2)≡(Branch s1 s2)=t1 ≡s1 ∧t2 ≡s2
new.Thecontributionofthispaperisinsteadfourideasthatmakeit
≡ =False
workinthisparticularsituation.Individually,theseideasmayseem
Ingeneral,whenaprogrammerdefinesanewtypeT inHaskell, small,buteachisessentialtothedesign.Inshort,thefourideasof
shemayenablepolymorphicequalityforthattypebyprovidingan thispaperare:
instanceofEq T.
However,Haskellprogramsoftenincludemanydatatypedefi- • Tomaketypeclasses“derivable”byusingrepresentationtypes
nitionsanditcanbetiresometodefineinstancesofEq forallof todefinedefaultmethodsforthem(Section2).
• Togenericallyrepresentthestructureofdatatypeswithalistof
dataconstructorembeddings(Section3).
• Tosupportspecializabletype-indexedoperationsbyparameter-
Permissiontomakedigitalorhardcopiesofallorpartofthisworkforpersonalor
classroomuseisgrantedwithoutfeeprovidedthatcopiesarenotmadeordistributed izingtherepresentationofdatatypeswithexplicitdictionaries
forprofitorcommercialadvantageandthatcopiesbearthisnoticeandthefullcitation (Section4).
onthefirstpage.Tocopyotherwise,torepublish,topostonserversortoredistribute
tolists,requirespriorspecificpermissionand/orafee. • To support the definition of functions indexed by parameter-
Haskell’06 September17,2006,Portland,Oregon,USA. izedtypesbydynamicallysupplyingexplicitdictionaries(Sec-
Copyright(cid:13)c 2006ACM1-59593-489-8/06/0009...$5.00. tion5).
1
In Section 7, we compare the capabilities of this proposal to Operationally,thisfunctionistheidentityfunctionforintegers.
existingwork.Forexample,thereareanumberofwaystogeneri- Forcompounddatastructures,suchaslistsandproducts,itdecom-
callyrepresentthestructureofdatatypes,and,morebroadly,there posesitsargumentandcallsitselfrecursively.Becausewecannot
areanumberofwaystodefinetype-indexedoperationsthatdonot accesstheintegersthatappearinaclosure,itisanerrortoapply
rely on representation types. However, our view is that the suc- thisfunctiontodatastructuresthatcontainsfunctions.Forallother
cessofanyproposalreliesoneaseofadoption.Therefore,wehave typesofarguments,thisfunctionreturns0.
workedhardtoidentifyasmallsetofmechanisms,implementable ThisdefinitiontypechecksintheInt branchbecauseweknow
withinthelanguageofanexistingHaskellcompiler,thatare,inour thatinthatbranchthetypeamustbeInt.So,eventhoughthetype
subjectiveview, usefulfor commonsituationsand providea pro- signaturesaysthebranchshouldreturnanInt,itisacceptableto
grammingmodelfamiliartofunctionalprogrammers. returntheargumentx oftypea.InGADTterminology,thetypea
An initial release of RepLib is available for download1 and is hasbeenrefinedtoInt.Furthermore,inthePair branch,weknow
compilable with the Glasgow Haskell Compiler (GHC), version thatthetypeamustbeatuple,sowemayimmediatelydestructthe
6.4.Thislibraryisnotportable.Itrequiresmanyoftheadvanced argument.Likewise,intheList branch,l mustbealistandsois
featuresofGHCthatarenotfoundinHaskell98:Higher-rankpoly- anappropriateargumentforfoldl.
morphism [29], lexically-scoped type variables [31], Generalized ThegsizeRfunctionmaybeappliedtoanyargumentcomposed
AlgebraicDatatypes(GADTs)[28],andundecidableinstancedec- ofInts,unit,booleans,characters,pairsandlists,whenprovided
larations.Furthermore,TemplateHaskell[30]automatesthedefi- with the appropriate type representation for that argument. For
nitionofrepresentationsfornewdatatypes.However,allofthese example,
extensionsareusefulintheirownrespect.
gsumR(Bool‘Pair‘(List Int))(True,[3,4])≡7
2. RepresentationTypesandTypeClasses NowcomparethedefinitionofgsumRwithatype-classbased
implementation.Wecouldrewritethegenericsumfunctionusing
Webeginbyshowinghowasimplerepresentationtypecanbeused
typeclassesas:
todefineadefaultmethodforaparticulartypeclass.Thepurpose
ofthisSectionisonlytointroducerepresentationtypesandclarify classGSum a where
therolesthattheyandtypeclassesplay.Thecodedevelopedhere gsum::a →Int
isforillustrativepurposesandnotpartoftheRepLiblibrary. instanceGSum Int where
Representation types [4] allow programmers to define type- gsum x =x
indexedoperationsastheywouldmanyotherfunctionsinHaskell— instanceGSum ()where
bypatternmatchinganalgebraicdatatype.However,arepresenta- gsum x =0
tiontypeisnoordinarydatatype:ItisanexampleofaGeneralized
instanceGSum Bool where
AlgebraicDatatype(GADT),arecentadditiontoGHC[28].
gsum x =0
For example, we define the representation type R below, fol-
instanceGSum Char where
lowingGADTnotation,bylistingallofitsdataconstructorswith
gsum x =0
theirtypes.
instance(GSum a,GSum b)⇒GSum (a,b)where
dataRa where gsum (x1,x2)=gsum x1 +gsum x2
Int ::RInt instance(GSum a)⇒GSum [a]where
Unit ::R() gsum l =foldl (λs x →(gsum x)+s)0l
Bool ::RBool
Withthisdefinition,onlyalittletypeinformationisrequiredat
Char ::RChar
thefunctioncalltodisambiguatetheNumclass.
Pair ::Ra →Rb →R(a,b)
Arrow ::Ra →Rb →R(a →b) gsum (True,[3,4::Int])≡7
List ::Ra →R[a]
Defininggenericsumwithtypeclasseslosesthesimplenotation
The important feature of the R type is that, even though it is a ofpatternmatching(includingthewildcardcase)buthasthreesig-
parameterized datatype, the data constructor determines the type nificant advantages over the representation-based definition: eas-
parameter.Forexample,thedataconstructorInt requiresthatthe ierinvocationasseenabove,astaticdescriptionofthedomainof
typeparameterbeInt.Thisreasoningworksinreverse,too.Ifwe gsum,andextensibilitytonewtypes.Bydefininggsumwithatype
knowthatthetypeofatermisR Int,thenweknowthattheterm classwecanstaticallypreventgsum frombeingcalledwithtypes
musteitherbethedataconstructorInt or⊥. thatcontainfunctions,andwecanextendthedefinitionofgsumat
GHCperformsthissortofreasoningwhentypecheckingtype- anytimewithacaseforanewuser-definedtype.
indexedfunctions.Forexample,wemightwriteanoperationthat Disregardingtheextensibilityissueforthemoment,weseethat
addstogetheralloftheIntsthatappearinadatastructure.(Inthis representation types make generic sum easier to define whereas
paper, all functions whose first argument is a representation type typeclassesmakeiteasiertouse.However,byusingtypeclasses
endwithacapital“R”.) andrepresentationtypestogether,wecangettheadvantagesofboth
definitions.
gsumR::Ra →a →Int
Consider a class Rep that includes all types that are repre-
gsumRInt x =x
sentable.
gsumR(Pair t1 t2)(x1,x2)=
gsumRt1 x1 +gsumRt2 x2 classRep a whererep::Ra
gsumR(List t)l =
The instances of this class are the data constructors of the
foldl (λs x →(gsumRt x)+s)0l
representationtype.
gsumR(Arrow t1 t2)f =error "urk!"
gsumR x =0 instanceRep Int whererep =Int
instanceRep () whererep =Unit
1http://www.cis.upenn.edu/∼sweirich/RepLib instanceRep Bool whererep =Bool
2
instanceRep Char whererep =Char 3.1 Representingdataconstructors
instance(Rep a,Rep b)⇒Rep (a,b)
The Con datatype describes data constructors (such as Leaf or
whererep =Pair rep rep Branch).
instance(Rep a,Rep b)⇒Rep (a →b)
whererep =Arrow rep rep dataCon ca =∀l.Con (Emb l a)(MTup cl)
instance(Rep a)⇒Rep [a]
Theparametera isthedatatypethattheseconstructorsbelongto.
whererep =List rep
The parameter c provides generality that will be used in the next
section.Here,thisparameterisalwaysinstantiatedbythetypeR.
WeusethisclassbydeclaringthattheclassGSumisasubclass
This datatype includes three components, a type l that is a type
ofRep,whichallowsadefaultdefinitionforthegsum methodin
list containing the types of the arguments of the constructor, an
termsofgsumR.
embedding-projectionpair,Emb l a,betweentheargumentsofthe
classRep a ⇒GSum a where constructorandthedatatypea,andMTup c l,therepresentation
gsum::a →Int ofthetypelist.
gsum =gsumRrep The∀inthedefinitionofConmeansthatitincludesanexisten-
tialcomponent[26]—anargumentoftypel isrequiredforthedata
Because of the default method, the instances of this class are constructorCon,butl doesnotappearasanargumenttothetype
trivial.Inparticular,thereisnorepeatedlogicbetweentheinstances constructorCon.Instead,l hidesatypelist(similartoaheteroge-
and the definition of gsumR. Instead, the instances “derive” the nouslist[20])sothatwecanuniformlyrepresentdataconstructors
definitionofgsumfortheseparticulartypes. thattakedifferentnumbersanddifferenttypesofarguments.Type
listsaredefinedbythefollowingtwosingle-constructordatatypes.
instanceGSum Int
(By convention, the type variable a stands for an arbitrary type,
instanceGSum ()
whilethetypevariablel standsforatypelist.)
instanceGSum Bool
instanceGSum Char dataNil =Nil
instance(GSum a,GSum b)⇒GSum (a,b) dataa :∗:l =a :∗:l
instanceGSum a ⇒GSum [a] infixr7:∗:
Defining the type-indexed operation in this manner demonstrates Note that type lists generalize n-tuples. For example, the type
thedifferentrolesthattypeclassesandrepresentationtypesshould (Int :∗:Char :∗:Nil)isisomorphictothepairtype(Int,Char).
play.Therepresentation-typeimplementationdescribesthebehav-
example1 ::(Int :∗:Char :∗:Nil)
iorofthetype-indexedoperationandthetypeclasslimitsitsdo-
main to acceptable types. Of course, the underlying implementa- example1 =2:∗:’b’:∗:Nil
tiongsumR isstillavailable,andtheusermustbecarefulnotto Thesecondingredientweneedintherepresentationofadata
call this operation with functions, but type classes make it more constructor for a datatype a is some way of manipulating argu-
convenienttousegsumcorrectly. ments of type a in a generic way. In particular, given an a, we
However,wehavegainedlittlesofar.Theextensibilityproblem wouldliketobeabletodeterminewhetheritisaninstanceofthis
remainsbecausethistypeclasscanonlybeinstantiatedforahand- particular data constructor, and if so extract its arguments. Also,
fuloftypes.Inthenextsection,wedevelopamoregeneralrepre- givenargumentsoftheappropriatetypes,weshouldbeabletocon-
sentationtypethatcanrepresentthestructureofarbitrarydatatypes structana.
andallowthedefinitionofgsumRbasedonthatstructure. Therefore,Conincludesanembedding-projectionpairbetween
the arguments of the constructor and the datatype, containing a
genericversionofaconstructorandagenericdestructor.
3. Datatype-genericprogramming
Therepresentationtypedefinedintheprevioussectioncouldonly dataEmb l a =Emb{to ::l →a,
representahandfuloftypes.Furthermore,itdoesnotallowusto from::a →Maybe l}
implementgsumRbasedonthestructureoftherepresentedtype.
For example, below are the embedding-projection pairs for the
Inparticular,wewouldliketodefinethebehaviorofgsumR for
constructorsoftheTreedatatype:
bothPairsandListswiththesamecode.
Inthissection,wedescribearepresentationtypethatcangener- rLeafEmb::Emb (a :∗:Nil)(Tree a)
icallyrepresentthestructureofallHaskell98datatypes.Consider rLeafEmb =Emb
thefollowingreviseddefinitionoftheRtype: {to =λ(a :∗:Nil)→(Leaf a),
from =λx →casex of
dataRa where
Leaf a →Just (a :∗:Nil)
Int ::RInt
→Nothing}
Char ::RChar
Arrow ::Ra →Rb →R(a →b) rBranchEmb::
Data ::DT →[Con Ra]→Ra Emb (Tree a :∗:Tree a :∗:Nil)(Tree a)
rBranchEmb =Emb
We represent all datatypes, both built-in and user-defined, with {to =λ(l :∗:r :∗:Nil)→(Branch l r),
thenewdataconstructorData.Therefore,wenolongerneedthe from =λx →casex of
constructorsList,Pair,Bool andUnit intheRtype.
Branch l r →Just (l :∗:r :∗:Nil)
TheData constructortakestwoarguments:informationabout
→Nothing}
the data type itself DT and information about each of the data
constructorsthatmakeupthedatatype(thelistofCon R a).In Finally,thethirdcomponentoftheCon datatypeisMTup cl,
Section3.1below,webeginourdiscussionwiththedesignofCon the representation of the type list l. We form this representation
andtheninSection3.2wecoverDT. withthefollowingGADT.
3
dataMTup cl where
dataVal c a =∀l.Val (Emb l a)(MTup c l)l
MNil::MTup cNil
(:+:)::Rep a ⇒ca →MTup cl →MTup c(a :∗:l) findCon::[Con c a]→a →Val c a
infixr7:+: findCon (Con emb reps:rest)x =case(from emb x)of
Just kids →Val emb reps kids
Like the R type, the type index describes what type list the term
Nothing →findCon rest x
represents.The(:+:)constructorincludesRep a initscontextso
findCon []x =error "Invalid representation"
that,asthislistisdestructed,thisrepresentationmaybeimplicitly
provided.Fornow,thecacomponentduplicatestherepresentation
foldl l::(∀a.Rep a ⇒ca →b →a →b)→b
inthecontextandisusefulfordisambiguation.Inthisway,thetype
MTup Rl representsalistoftypes. →(MTup cl)→l →b
foldl l f b MNil Nil =b
example2 ::MTup R(Int :∗:Char :∗:Nil)
foldl l f b (ra :+:rs)(a :∗:l)=foldl l f (f ra b a)rs l
example2 =Int :+:Char :+:MNil
map l::(∀a.Rep a ⇒c a →a →a)
ToformtherepresentationsofthedataconstructorsLeaf and
→MTup c l →l →l
Branch, we need the representation of the type a to satisfy the
map l t MNil Nil =Nil
classconstraintof(:+:).The∀inthetypeannotationsofrLeaf and
map l t (r :+:rs)(a :∗:a1)=(t r a :∗:map l t rs a1)
rBranchbindthelexically-scopedtypevariableasothatitmaybe
usedinthetypeannotationsthatspecifywhichtyperepresentations
touse. Figure1. Libraryoperationsfordefiningtype-indexedfunctions
rLeaf ::∀a.Rep a ⇒Con R(Tree a)
rLeaf =Con rLeafEmb ((rep::Ra):+:MNil)
of Show below displays a representation type. Note that pattern
rBranch::∀a.Rep a ⇒Con R(Tree a) matching allows a natural definition for showing a list of type
rBranch =Con rBranchEmb parameters.
((rep::R(Tree a)):+:
instanceShow (Ra)where
(rep::R(Tree a)):+:MNil)
show Int ="Int"
ThedefinitionofCondescribedinthissectioncontainsonlythe show Char ="Char"
minimum information required for representating data construc- show (Arrow r1 r2)=
tors.InthetheRepLiblibraryimplementation,thisdatatypealso "("++(show r1)++" -> "++(show r2)++")"
includesadditionalinformationaboutthedataconstructor,suchas show (Data (DT str reps) )=
astringcontainingthenameoftheconstructor,itsfixity,andthe "("++str ++show reps++")"
names of any record labels. Here, we have elided those compo- instanceShow (MTup Rl)where
nents. show MNil =""
show (r :+:MNil)=show r
3.2 TheDT type
show (r :+:rs)=" "++show r ++show rs
TheDT componentofthedatatyperepresentationcontainsinfor-
InthecaseofData,theinformationaboutthedataconstructorsis
mation instrinsic to the datatype itself, including the name of the
ignored.Insteadthestringandrepresentationsofthetypeparame-
datatypeandtherepresentationofitsparameters.
tersareused.
dataDT =∀l.DT String (MTup Rl) The representation of the datatype need only be created once,
whenthedatatypeisdefined.(However,evenifitisnotdonethen,
For example, we can represent the type Tree with the following
itmaybecreatedbyanymodulethatknowsitsdefinition.)Inthis
instanceoftheRepclass.
way,Data mayrepresentawiderangeofdatatypes,includingpa-
instanceRep a ⇒Rep (Tree a)where rameterizeddatatypes(suchasTree),mutuallyrecursivedatatypes,
rep =Data (DT "Tree"((rep::Ra):+:MNil)) nesteddatatypes,andsomeGADTs.Section6.3discussestheex-
[rLeaf,rBranch] pressiveness of this representation type in more detail. Further-
more,giventhedefinitionofsuchdatatypes(exceptforGADTs),
Includingthenameofthedatatypeinitsrepresentationandthe
RepLibincludesTemplateHaskellcodetoautomaticallygenerate
representationsofanytypeparametersisnecessarytodistinguish
itsrepresentationandinstancedeclarationfortheReptypeclass.
between types that have the same structure. Therefore type-safe
cast[38]oftype
3.3 Examplesoftype-indexedfunctions
cast::(Rep a,Rep b)⇒a →Maybe b
Once we can represent datatypes structurally, we can define op-
andtherelatedgeneralizedcast erations based on that structure. Consider the implementation of
genericsumwiththisnewrepresentation:
gcast::(Rep a,Rep b)⇒c a →Maybe (c b)
gsumR::Ra →a →Int
can be implemented. Without this information, these operations
gsumRInt x =x
cannotenforcethedistinctionbetweenisomorphictype.2
gsumR(Arrow r1 r2) f =error "urk"
Also,displayingtherepresentationoftypessuchasTree Intor
gsumR(Data rdt cons)x =findCon cons
Tree Bool requiresbothofthecomponentsofDT.Theinstance
wherefindCon (Con emb reps:rest)=
case(from emb x)of
2While the basic cast may be implemented by decomposing and recon-
Just kids →gsumRl reps kids
structingitsargument,theimplementationofthegeneralizedcastrequires
theuseofanunsafetypecast.However,forpracticalreasons,basiccastis Nothing →findCon rest
alsoimplementedwithprimUnsafeCoerce#intheimplementation. findCon []=error "Invalid representation"
4
foldl l (λra bb a →(deepSeqRra a).bb)id reps args
--Typestructure-baseddefinition
deepSeqR =seq
gsumR::Ra →a →Int
gsumRInt x =x Unlikemanyothertype-directedoperations,deepSeq makessense
gsumR(Arrow r1 r2) f =error "urk" for all representable types. Therefore, we do not use a type class
gsumR(Data rdt cons)x = to govern its usage, only a wrapper to provide the representation
argumentfromthecontext.
case(findCon cons x)of
Val reps kids → deepSeq::Rep a ⇒a →b →b
foldl l (λr a b →(gsumRr a)+b)0reps kids deepSeq =deepSeqRrep
gsumR x =0
The operations gsum and deepSeq are examples of type-
--Typeclasswithdefaultdefinition indexedconsumers—functionsthatusetypeinformationtodecom-
classRep a ⇒GSum a where poseanargumentofthattype.RepLibcanalsodefineproducers.
gsum::a →Int Thesefunctions,suchasthezerooperationbelow,createvaluesof
agiventype.
gsum =gsumRrep
--Enablegsumforcommontypes classRep a ⇒Zero a where
zero::Rep a ⇒a
instanceGSum Int
zero =zeroRrep
instanceGSum Bool
--etc... zeroR::Ra →a
zeroRInt =0
Figure2. GenericSum zeroRChar =’0’
zeroR(Arrow z1 z2)=const (zeroRz2)
zeroR(Data dt (Con emb rec:rest))=
gsumR x =0 to emb (fromTup zeroRrec)
gsumRl::MTup Rl →l →Int fromTup::(∀a.Rep a ⇒ca →a)→MTup cl →l
gsumRl MNil Nil =0 fromTup f MNil =Nil
gsumRl (r :+:rs)(a :∗:l)=gsumRr a+gsumRl rs l fromTup f (b :+:l)=(f b):∗:(fromTup f l)
The new part of this example is the case for Data. Given an “Scrap your boilerplate” programming Representation types
argumentoftypea,theauxiliaryfunctionfindConiteratesthrough can implement many of the same operations as the “Scrap your
the data constructors until it finds the appropriate one and then boilerplate”(SYB)librarybyLa¨mmelandPeytonJones[21].For
calls gsumR on all of the arguments to this constructor, adding example, one part of the SYB library defines generic traversals
theresultstogether. over datatypes, using the type-indexed operations mkT, mapT
NotethatfindCon shouldneverreachthe[]case.Ifwehave andeverywhere.Below,weshowhowtoimplementthoseopera-
correctlyrepresentedthedatatype,thenoneofthegenericdestruc- tionswithrepresentationtypes.
torswillbeabletodecomposethetype.Thisloopingpatternap- Atraversalisafunctionthathasaspecificbehaviorforapar-
pearsoftenintype-indexedcode,soitmakessensetofactoritout. ticulartype(orsetoftypes)butistheidentityfunctioneverywhere
InFigure1,wedefinethefunctionfindConthatperformsthisloop. else.Inthissetting,traversalshavethefollowingtype:
Theresultofthisfunctionmustexistentiallybindthetypelist—so
wealsodefineanewdataconstructorVal thatcontainstheargu- typeTraversal =∀a.Rep a ⇒a →a
mentsofthedataconstructor,therepresentationoftheirtypes,and ThemkT functionconstructstraversalsbyliftingamonomor-
theembedding-projectionpairforthatdataconstructor. phicfunctionoftypet →t tobeaTraversal.
Furthermore,oncewehavefoundtheappropriatedataconstruc-
tor,thenextstepisoftentoiterateoverthelistofkids.Therefore, mkT ::(Rep a,Rep b)⇒(a →a)→b →b
Figure1alsocontainstheanaloguesoffoldlandmapfortypelists. mkT f =case(cast f)of
With these operations, we can rewrite the Data branch for Just g →g
gsumR moresuccinctlyasshowninFigure2.(Notethatbecause Nothing →id
of the existential component of Val, we must use case instead
Next,themapT functionbelowextendsabasictraversaltoa“one-
of let to pattern match the result of findCon.) This Figure is
layer”traversalbymapingthetraversalacrossthesubcomponents
the complete definition of generic sum, including the type class
of a data constructor. Note that the annotation of the return type
definitiondiscussedintheprevioussection.Ifaprogrammerwould
a → a bindsthelexicallyscopedtypevariablea sothatwemay
liketoderiveaninstanceofGSum foranewtype,heneedonly
refertoitintheannotationRa.
makesurethattherepresentationofthattypeisavailableandthen
createthetrivialinstanceofGSumforthenewtype. mapT ::Traversal →Traversal
TheoperationsinFigure1makethedefinitionsofsometype- mapT t::a →a =
indexed functions very concise. For example, deepSeq below is case(rep::Ra)of
an operation that fully evaluates its first argument. (The built-in (Data str cons)→λx →
Haskelloperationseqonlyreducesitsfirstargumenttotheouter- case(findCon cons x)of
mostdataconstructor.Thisoperationalsorecursivelyevaluatesall Val emb reps kids →
ofthekidsofthedataconstructortoo.) to emb (map l (const t)reps kids)
→id
deepSeqR::Ra →a →b →b
deepSeqR(Data dt cons)=λx → Finally, the everywhere combinator applies the traversal to
case(findCon cons x)of everynodeinadatatype.Thedefinitionofeverywhere isexactly
Val reps args → thesameasintheSYBlibrary.
5