Haskell’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 <[email protected]>. 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 [email protected], 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: [email protected] 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 [email protected] 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