In our love a64256air with the tree it is parsed pattern matched pruned and printed A pretty printer is a tool often a library of routines that aids in converting a tree into text The text should occupy a minimal number of lines while retaining ind ID: 11428
Download Pdf The PPT/PDF document "A prettier printer Philip Wadler Joyce K..." is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
2Aprettierprinter1AsimpleprettyprinterTobegin,weconsiderthesimplecasewhereeachdocumenthasonlyonepossiblelayout|thatis,noattemptismadetocompressstructureontoasingleline.Therearesixoperatorsforthispurpose.()::Doc-Doc-Docnil::Doctext::String-Docline::Docnest::Int-Doc-Doclayout::Doc-StringHereistheassociativeoperationthatconcatenatestwodocuments,whichhastheemptydocumentnilasitsleftandrightunit.Thefunctiontextconvertsastringtothecorrespondingdocument,andthedocumentlinedenotesalinebreak;weadopttheconventionthatthestringpassedtotextdoesnotcontainnewlinecharacters,sothatlineisalwaysusedforthispurpose.Thefunctionnestaddsindentationtoadocument.Finally,thefunctionlayoutconvertsadocumenttoastring.(Inpractice,onemightchoosetomake(text"\n")behavelikeline,where"\n"isthestringconsistingofasinglenewline.)Onesimpleimplementationofsimpledocumentsisasstrings,withasstringconcatenation,nilastheemptystring,textastheidentityfunction,lineasthestringconsistingofasinglenewline,nestiasthefunctionthataddsispacesaftereachnewline(toincreaseindentation),andlayoutastheidentityfunction.Thissimpleimplmentationisnotespeciallyecient,sincenestingexamineseverycharacterofthenesteddocument,nordoesitgeneralizeeasily.Wewillconsideramorealgebraicimplementationshortly.Notethatindentationisaddedonlyatanexplicitnewline,notatthebeginningofastring.ReadersfamiliarwithHughes'sprettyprintermayndthischoicesurprising,butitispreciselythischoicethatenablestheuseofoneconcatenationoperatorratherthantwo.Asanexample,hereisasimpletreedatatype,andfunctionstoconvertatreetoadocument.dataTree=NodeString[Tree]showTree(Nodests)=textsnest(lengths)(showBracketts)showBracket[]=nilshowBracketts=text"["nest1(showTreests)text"]"showTrees[t]=showTreetshowTrees(t:ts)=showTreettext","lineshowTreestsThisproducesoutputinthefollowingstyle.aaa[bbbbb[ccc, 4AprettierprinterAndhereisitsnormalform.text"bbbbb["nest2linetext"ccc,"nest2linetext"dd"nest0linetext"]"Hence,thedocumentprintsasfollows.bbbbb[ccc,dd]Thefollowinglawsareadequatetoreduceadocumenttonormalform,takentogetherwiththefactthatisassociativewithunitnil.text(s++t)=textstextttext""=nilnest(i+j)x=nesti(nestjx)nest0x=xnesti(xy)=nestixnestiynestinil=nilnesti(texts)=textsAllbutthelastlawcomeinpairs:eachlawonabinaryoperatorispairedwithacorrespondinglawforitsunit.Therstpairoflawsstatethattextisahomo-morphismfromstringconcatenationtodocumentconcatenation.Thenextpairoflawsstatethatnestisahomomorphismfromadditiontocomposition.Thepairafterthatstatethatnestdistributesthroughconcatenation.Thelastlawstatesthatnestingisabsorbedbytext.Inreducingatermtonormalform,therstfourlawsareappliedlefttoright,whilethelastthreeareappliedrighttoleft.Wecanalsogivelawsthatrelateadocumenttoitslayout.layout(xy)=layoutx++layoutylayoutnil=""layout(texts)=slayout(nestiline)='\n':copyi''Thersttwolawsstatethatlayoutisahomomorphismfromdocumentconcatena-tiontostringconcatenation.Inthissense,layoutistheinverseoftext,whichispreciselywhatthenextlawstates.Thenallawstatesthatthelayoutofanestedlineisanewlinefollowedbyonespaceforeachlevelofindentation.Asimple,butadequate,implementationcanbederiveddirectlyfromtheal-gebraofdocuments.Werepresentadocumentasaconcatenationofitems,whereeachitemiseitheratextoralinebreakindentedagivenamount. 6Aprettierprinter2AprettyprinterwithalternativelayoutsWenowconsiderdocumentswithmultiplepossiblelayouts.Whereasbeforewemightviewadocumentasequivalenttoastring,nowwewillviewitasequivalenttoasetofstrings,eachcorrespondingtoadierentlayoutofthesamedocument.Thisextensionisachievedbyaddingasinglefunction.group::Doc-DocGivenadocument,representingasetoflayouts,groupreturnsthesetwithonenewelementadded,representingthelayoutinwhicheverythingiscompressedononeline.Thisisachievedbyreplacingeachnewline(andthecorrespondingindentation)withtextconsistingofasinglespace.(Variantsmightbeconsideredwhereeachnewlinecarrieswithitthealternatetextitshouldbereplacedby.Forinstance,somenewlinesmightbereplacedbytheemptytext,otherswithasinglespace.)Thefunctionlayoutisreplacedbyonethatchoosestheprettiestamongasetoflayouts.Ittakesasanadditionalparameterthepreferredmaximumlinewidthofthechosenlayout.pretty::Int-Doc-String(Variantsmightbeconsideredwithadditionalparameters,forinstancea`ribbonwidth'indicatingthemaximumnumberofnon-indentationcharactersthatshouldappearonaline.)Asanexample,hereisarevisionoftherstformofthefunctiontoconvertatreetoadocument,whichdiersbytheadditionofacalltogroup.showTree(Nodests)=group(textsnest(lengths)(showBracketts))Ifthepreviousdocumentisprintedwithpretty30,thisdenitionproducesthefollowingoutput.aaa[bbbbb[ccc,dd],eee,ffff[gg,hhh,ii]]Thiststreesontoonelinewherepossible,butintroducessucientlinebreakstokeepthetotalwidthlessthan30characters.Toformalizethesemanticsofthenewoperations,weaddtwoauxiliaryoper-ators.|000;()::Doc|000;-Doc|000;-Docflatten::Doc|000;-DocThe|000;operatorformstheunionofthetwosetsoflayouts.Theflattenoperatorreplaceseachlinebreak(anditsassociatedindentation)byasinglespace.Adocumentalwaysrepresentsanon-emptysetoflayouts,wherealllayoutsintheset attentothesamelayout.Asaninvariant,werequirein(x|000;y)thatall 8AprettierprinterdataDoc=Nil|String`Text`Doc|Int`Line`Doc|Doc`Union`DocTheseconstructorsrelatetothedocumentoperatorsasfollows.Nil=nils`Text`x=textsxi`Line`x=nestilinexx`Union`y=x|000;yWenowhavetwoinvariantson(x`Union`y).Asbefore,werequirethatxandy attentothesamelayout.Additionally,werequirethatnorstlineofadocumentinxisshorterthansomerstlineofadocumentiny;or,equivalently,thateveryrstlineinxisatleastaslongaseveryrstlineiny.WemustinsuretheseinvariantswhereverwecreataUnion.Toachieveacceptableperformance,wewillexploitthedistributivelaw,andusetherepresentation(s`Text`(x`Union`y))inpreferencetotheequivalent((s`Text`x)`Union`(s`Text`y)).Forinstance,considerthedocumentgroup(group(group(group(text"hello"ကlinetext"a")linetext"b")linetext"c")linetext"d")Thishasthefollowingpossiblelayouts:helloabchelloabhelloahellocbacbcTolaythisoutwithinamaximumwidthof5,wemustpickthelastofthese{andwewouldliketoeliminatetheothersinonefellswoop.Toachievethis,wepickarepresentationthatbringstothefrontanycommonstring.Forinstance,werepresenttheabovedocumentintheform"hello"`Text`((""`Text`x)`Union`(0`Line`y))forsuitabledocumentsxandy.Here"hello"hasbeenfactoredoutofallthelayoutsinxandy,and""hasbeenfactoredoutofallthelayoutsinx.Since"hello"followedby""occupies6charactersandthelinewidthis5,wemayimmediatelychoosetherightoperandof`Union`withoutfurtherexaminationofx,asdesired. 10Aprettierprintertextsgroupx={definitionText}s`Text`groupxDistributionisusedtobringtogetherthetwoinstancesoftextgeneratedbythedenitionofgroup.Aswesawabove,thisfactoringiscrucialinecientlychoosingarepresentation.Theotherlinesofgroupandflattenarealsoeasilyderived.Thelastlineofeachfollowsfromtheinvariantthatthetwooperandsofaunionboth attentothesamedocument.Next,itisnecessarytochoosethebestamongthesetofpossiblelayouts.Thisisdonewithafunctionbest,whichtakesadocumentthatmaycontainunions,andreturnsadocumentcontainingnounions.Amoment'sthoughtrevealsthatthisoperationrequirestwoadditionalparameters:onespeciestheavailablewidthw,andthesecondspeciesthenumberofcharacterskalreadyplacedonthecurrentline(includingindentation).Thecodeisfairlystraightforward.bestwkNil=Nilbestwk(i`Line`x)=i`Line`bestwixbestwk(s`Text`x)=s`Text`bestw(k+lengths)xbestwk(x`Union`y)=betterwk(bestwkx)(bestwky)betterwkxy=iffits(w-k)xthenxelseyThetwomiddlecasesadjustthecurrentposition:foranewlineitissettotheindentation,andfortextitisincrementedbythestringlength.Foraunion,thebetterofthebestofthetwooptionsisselected.Itisessentialforeciencythattheinnercomputationofbestisperformedlazily.Bytheinvariantforunions,norstlineoftheleftoperandmaybeshorterthananyrstlineoftherightoperand.Hence,bythecriteriongivenpreviously,therstoperandispreferredifitts,andthesecondoperandotherwise.Itislefttodeterminewhetheradocument'srstlinetsintowspaces.Thisisalsostraightforward.fitswx|w0=FalsefitswNil=Truefitsw(s`Text`x)=fits(w-lengths)xfitsw(i`Line`x)=TrueIftheavailablewidthislessthanzero,thenthedocumentcannott.Otherwise,ifthedocumentisemptyorbeginswithanewlinethenittstrivially,whileifthedocumentbeginswithtextthenittsiftheremainingdocumenttsintheremainingspace.Handlingnegativewidthsisnotmerelyesoteric,asthecasefortextmayyieldanegativewidth.Nocaseisrequiredforunions,sincethefunctionisonlyappliedtothebestlayoutofaset.Finally,toprettyprintadocumentoneselectsthebestlayoutandconvertsittoastring. 12Aprettierprinternil=NILxy=x:ကynestix=NESTixtexts=TEXTsline=LINEAgain,asaninvariant,werequirein(x|000;:y)thatalllayoutsinxandy attentothesamelayout,andthatnorstlineinxisshorterthananyrstlineiny.Denitionsofgroupandflattenarestraightforward.groupx=flattenx|000;:xflattenNIL=NILflatten(x:y)=flattenx:flattenyflatten(NESTix)=flattenxflatten(TEXTs)=TEXTsflattenLINE=TEXT""flatten(x|000;:y)=flattenxThesefollowimmediatelyfromtheequationsgivenpreviously.Therepresentationfunctionmapsalistofindentation-documentpairsintothecorrespondingdocument.repz=fold()nil[nestix|(i,x)z]Theoperationtondthebestlayoutofadocumentisgeneralizedtoactonalistofindentation-documentpairs.Thegeneralizedoperationisdenedbycomposingtheoldoperationwiththerepresentationfunction.bewkz=bestwk(repz)(hypothesis)Thenewdenitioniseasilyderivedfromtheold.bestwkx=bewk[(0,x)]bewk[]=Nilbewk((i,NIL):z)=bewkzbewk((i,x:y):z)=bewk((i,x):(i,y):z)bewk((i,NESTjx):z)=bewk((i+j,x):z)bewk((i,TEXTs):z)=s`Text`bew(k+lengths)zbewk((i,LINE):z)=i`Line`bewizbewk((i,x|000;:y):z)=betterwk(bewk((i,x):z))(bewk((i,y):z))Hereisthederivationoftherstline.bestwkx={0isunitfornest}bestwk(nest0x) 14Aprettierprinter4ExamplesAnumberofconveniencefunctionscanbedened.x+000;y=xtext""yx/000;y=xlineyfolddocf[]=nilfolddocf[x]=xfolddocf(x:xs)=fx(folddocfxs)spread=folddoc+000;()stack=folddoc/000;()Thereadermaycomeupwithmanyothers.Oftenalayoutconsistsofanopeningbracket,anindentedportion,andaclosingbracket.bracketlxr=group(textlnest2(linex)linetextr)Thefollowingabbreviatesthesecondtreelayoutfunction.showBracket'ts=bracket"["(showTrees'ts)"]"Anotheruseofbracketappearsbelow.Thefunctionfillwordstakesastring,andreturnsadocumentthatllseachlinewithasmanywordsaswillt.Ituseswords,fromtheHaskellstandardlibrary,tobreakastringintoalistofwords.x+/00;y=x(text""|000;:line)yfillwords=folddoc+/00;().maptext.wordsRecallthatwedonotexpose|000;:totheuser,butx+/00;ymaybesafelyex-posed,becauseitsatisestheinvariantrequiredby|000;:.Bothtext""andline attentothesamelayout,andtheformerhasalongerrstlinethanthelatter.Alternatively,onecanrewritetheabovebynotingthat(text""|000;:line)isequivalentto(groupline).Avariantoffillwordsisfill,whichcollapsesalistofdocumentsintoadocument.Itputsaspacebetweentwodocumentswhenthisleadstoreason-ablelayout,andanewlineotherwise.(IstolethisfunctionfromPeytonJones'sexpansionofHughes'sprettyprinterlibrary.)fill[]=nilfill[x]=xfill(x:y:zs)=(flattenx+000;fill(flatteny:zs))|000;:(x/000;fill(y:zs)) 16Aprettierprinterhref="http://www.eg.com/" -52;倀link/a00;elsewhere./p00;Observehowembeddedmarkupeitheris attenedorappearsonalinebyitself.Ifthetwooccurrencesofflattendidnotappearinfill,thenonemighthavelayoutssuchasthefollowing.color="red"font="Times"size="10"p-52;倀Hereissomem00;emphasized/em0;text.Hereisahref="http://www.eg.com/" ]TJ; 10.;ѡ ;-12.;॑ ;Td[0;link/a00;elsewhere./p00;Thislatterlayoutisnotsopretty,becausethestartandclosetagsoftheemphasisandanchorelementsarecrammedtogetherwithothertext,ratherthangettinglinestothemselves.5RelatedworkandconclusionAlgebraHugheshastwofundamentallydierentconcatenationoperators.Hishor-izontalconcatenationoperator(alsowritten)iscomplex:anynestingontherstlineofthesecondoperandiscancelled,andallsucceedinglinesofthesecondoperandmustbeindentedasfarasthetextonthelastlineoftherstoperand.Hisverticalconcatenationoperator(written$$)issimple:italwaysaddsanewlinebetweendocuments.Foradetaileddescription,seeHughes(1995).Hughes'soperatorsarebothassociative,butassociatewitheachotherinonlyoneoftwopossibleways.Thatis,ofthetwoequations,x$$(yz)=(x$$y)zx(y$$z)=(xy)$$ztherstholdsbuttheseconddoesnot.Horizontalconcatenationhasaleftunit,butbecausehorizontalcompositioncancelsnestingofitssecondargument,itisinherentlyinimicabletoarightunit.Verticalconcatenationalwaysaddsanewline,soithasneitherunit.Incomparison,hereeverythingisbasedonasingleconcatenationoperatorthatisassociativeandhasbothaleftandrightunit.Wecandeneananalogueofverticalconcatenation.x/000;y=xlineyItfollowsimmediatelythat/000;isassociative,andthatand/000;associatewitheachotherbothways,though/000;hasneitherunit. 18Aprettierprinterexploitingthefactthattheindentationoperatordistributesthroughconcatenation.Onemightsay,theprettierprinterhatchedinBird'snest.6AcknowledgementsIthankRichardBird,KoenClaessen,JohnHughes,SamKamin,DanielJ.P.Leijen,JereyLewis,ChrisOkasaki,SimonPeytonJones,andAndreasRossbergforcommentsonearlierversionsofthisnote.7Code--Theprettyprinterinfixr5|000;:infixr6:infixr6dataDOC=NIL|DOC:DOC|NESTIntDOC|TEXTString|LINE|DOC|000;:DOCdataDoc=Nil|String`Text`Doc|Int`Line`Docnil=NILxy=x:ynestix=NESTixtexts=TEXTsline=LINEgroupx=flattenx|000;:xflattenNIL=NILflatten(x:y)=flattenx:flattenyflatten(NESTix)=NESTi(flattenx)flatten(TEXTs)=TEXTsflattenLINE=TEXT""flatten(x|000;:y)=flattenxlayoutNil="" 20Aprettierprinterfill[x]=xfill(x:y:zs)=(flattenx+000;fill(flatteny:zs))|000;:(x/000;fill(y:zs))--TreeexampledataTree=NodeString[Tree]showTree(Nodests)=group(textsnest(lengths)(showBracketts))showBracket[]=nilshowBracketts=text"["nest1(showTreests)text"]"showTrees[t]=showTreetshowTrees(t:ts)=showTreettext","lineshowTreestsshowTree'(Nodests)=textsshowBracket'tsshowBracket'[]=nilshowBracket'ts=bracket"["(showTrees'ts)"]"showTrees'[t]=showTreetshowTrees'(t:ts)=showTreettext","lineshowTreeststree=Node"aaa"[Node"bbbbb"[Node"ccc"[],Node"dd"[]],Node"eee"[],Node"ffff"[Node"gg"[],Node"hhh"[],Node"ii"[]]]testtreew=putStr(prettyw(showTreetree))testtree'w=putStr(prettyw(showTree'tree))--XMLexampledataXML=EltString[Att][XML]|TxtString 22Aprettierprinter[Hughes1995]JohnHughes.Thedesignofapretty-printerlibrary.InJ.JeuringandE.Meijer,editors,AdvancedFunctionalProgramming,SpringerVerlagLNCS925,1995.[Oppen1980]DerekOppen.Pretty-printing.ACMTransactionsonProgrammingLanguagesandSystems,2(4):1980.[PeytonJones1997]SimonPeytonJones.Haskellpretty-printerlibrary,1997.Availablefromhttp://www.haskell.org/libraries/#prettyprinting.