ebook img

A Practical Study of Control in Objected-Oriented--Functional--Logic Programming with Paisley PDF

0.2 MB·
Save to my drive
Quick download
Download
Most books are stored in the elastic cloud where traffic is expensive. For this reason, we have a limit on daily download.

Preview A Practical Study of Control in Objected-Oriented--Functional--Logic Programming with Paisley

A Practical Study of Control in Objected-Oriented–Functional–Logic Programming with Paisley BaltasarTranco´nyWidemann MarkusLepper IlmenauUniversityofTechnology,DE <semantics/>GmbH,DE [email protected] Paisleyisanextensiblelightweightembeddeddomain-specificlanguagefornondeterministicpattern matchinginJava. UsingsimpleAPIsandprogrammingidioms,itbringsthepoweroffunctional–logic processingofarbitrarydataobjectstotheJavaplatform,withoutconstrainingtheunderlyingobject- orientedsemantics. HerewepresentanextensiontothePaisleyframeworkthataddspattern-based control flow. It exploits recent additions to the Java language, namely functional interfaces and lambdaexpressions,foranexplicitandtransparentcontinuation-passingstyleapproachtocontrol. Weevaluatethepracticalimpactofthenovelfeaturesonareal-worldcasestudythatreengineers athird-partyopen-sourceprojecttousePaisleyinplaceofconventionalobject-orienteddataquery idioms. We find the approach viable for incremental refactoring of legacy code, with significant qualitativeimprovementsregardingseparationofconcerns,clarityandintentionality,thusmakingfor easiercodeunderstanding,testinganddebugging. Keywords: pattern matching; control flow; embedded domain-specific language; object orientation; refactoring 1 Introduction Theobject-orientedparadigm,initspureform,suffersfromstronglyasymmetricexpressivitywithrespect to structured data. On the one hand, constructors and factory methods allow for a term-like notation for the construction of data. On the other hand, the corresponding dedicated tools for the query and deconstructionofdata,namelydynamictypetests,castsandgettermethods,arenotonlyverydifferent in appearance, but also markedly less expressive and compositional. Programming style patterns and idiomssuchasiteratorsandvisitorshavebeendevelopedtoamendtheissue,butsufferfromrestricted applicabilityandheavyimpactoncodestructure,resultinginimpreciseandclumsypracticalusage. Bycontrast,declarativelanguagestypicallysupportanotationthatisdirectlyinverseto,andhence asclear,lightweight,preciseandexpressiveas,dataconstruction: patternmatching. Thedenotational semantics ofpatterns rely on theinvertible algebraic structureof declarative datamodels. Hence they donotcarryovertoarbitraryobject-orienteddatamodels,whosebasicprinciplessuchastranscendental identity,mutablestateanddataabstractionarefundamentallyatodds. Multi-paradigmlanguagessuchasScala[4]havedemontratedthatobject-orientedprogrammingcan benefit greatly from an approach to pattern matching that is more operational and hence adequate to imperativeprogramsemantics. Bycontrast,approachessuchasJMatch[3],whichimposedeclarative pseudo-semanticsonobjectsandimperativecode,haveneversuccessfullyreachedthemainstream. WehavedesignedPaisley[6]asalightweightembeddeddomain-specificlanguage,thatisalibraryof classesandidioms,forpatternmatchinginJava. Paisleyintegratescloselywiththeimperativeobject- orientedparadigm,evencloserthanScala’sbuilt-inpatterns. Itsupportsuserextensions,combinatorial S.SchwarzandJ.Voigtla¨nder(Eds.):29thand30thWorkshops on(Constraint)LogicProgrammingand24thInternational WorkshoponFunctionaland(Constraint)LogicProgramming (WLP’15/’16/WFLP’16). EPTCS234,2017,pp.150–164,doi:10.4204/EPTCS.234.11 Tranco´nyWidemann&Lepper 151 publicclassPair{ Pattern(cid:104)Object(cid:105) isPair=isInstanceOf(Pair.class); Motif(cid:104)Pair,Object(cid:105) asPair=forInstancesOf(Pair.class); privateObjectcar,cdr; publicPair (Objectcar, Pattern(cid:104)Object(cid:105) pair (Pattern(cid:104)Object(cid:105) pcar, Objectcdr) { Pattern(cid:104)Object(cid:105) pcdr) { this.car=car; returnasPair.apply(car.apply(pcar) this.cdr=cdr; .and(cdr.apply(pcdr))); } } publicObjectgetCar() { Motif(cid:104)Object,Pair(cid:105) car=transform(Pair::getCar); returncar; } publicObjectgetCdr() { Motif(cid:104)Object,Pair(cid:105) cdr=transform(Pair::getCdr); returncdr; } publicstaticfinalObjectempty; Pattern(cid:104)Object(cid:105) isEmpty=eq(Pair.empty); } Figure1: LISPlists,Javadatamodel(left)andPaisleypatternlibrary(right) abstractions, nondeterminism by backtracking, encapsulated search, and metaprogramming, without requiringchangestoeithertheJavahostlanguageorthecodeofthedataobjectmodelstobequeried. Inpastpapers,wehavedemonstratedhowtousePaisleytosanitizelegacyqueryinterfaces[5],how to combine nondeterminism and search-plan metaprogramming to solve logical puzzles [7], and how toexpresscomplexrelationalqueriesinpattern(Kleene)algebra[8],respectively. Insummary,Paisley turns Java into an effective functional–logic programming language, without constraining the use of featuresoftheobject-orientedhostenvironment. However,thedemonstrationshavesofarfocusedon encapsulatedsearch,andomittedadifferentaspectthatisubiquitousindeclarativepatternmatching: the jointspecificationofdataandcontrolflowincasedistinctionsbypatternmatchingclauses. Thepresentpaperfillsthisgap. TheJavalanguagehasadopted,initsrecentversion8,mechanisms for local functional programming that are well-integrated with the object-oriented background. We demonstratehowtousethesetoencodetherighthandsidesofpatternmatchingclausesascontinuations, suchthattheordinaryJavameansforclauseselection,namelyconditionalstatementsandshort-circuiting Booleanoperators,canbeusedfreelyandeffectively. Unlikefortheprecedingpapers[7,8],weillustrate thereal-worlduseofthisnovelexpressivitynotbyconstructinganewprogramforthepurpose,butinstead byreengineeringpartsofanexistingthird-partyopen-sourceproject. Wediscussandevaluatetheimpact ofourmodificationsbothqualitativelyandquantitatively. 2 Paisley in a Nutshell As a running example, consider Figure 1 (left): a simple data model of LISP-style universal lists, implementedinJavainobject-orientedtextbookstyle. Itisasimplemattertodenotetheconstruction ofalist,forinstanceofthreeelementsx,yandz. Itishoweveraverydifferentmattertousethepublic APItodenotetheinverseoperation: checkingwhetheragivenlistcontainsexactlythreeelements,andif so,extractthemasx,yandz,orotherwisedosomethingelse. SeeFigure2(topandcenter). Thestyle 152 ControlforPaisley list1=newPair(x,newPair(y,newPair(z,empty))); booleansuccess=false; // [S] if (list1instanceofPair) { // [T] Pairpair1= (Pair)list1; // [C] Objectx=pair1.getCar(); // [B,P] Objectlist2=pair1.getCdr(); // [b,P] if (list2instanceofPair) { // [T] Pairpair2= (Pair)list2; // [C] Objecty=pair2.getCar(); // [B,P] Objectlist3=pair2.getCdr(); // [b,P] if (list3instanceofPair) { // [T] Pairpair3= (Pair)list3; // [C] Objectz=pair3.getCar(); // [B,P] Objectlist4=pair3.getCdr(); // [b,P] if (list4==empty) { // [T] succeed(x,y,z); // [R] success=true; // [S] } } } } if (!success) // [S] fail(); // [R] Variable(cid:104)Object(cid:105) x=newVariable(cid:104)(cid:105)(), y=newVariable(cid:104)(cid:105)(), z=newVariable(cid:104)(cid:105)(); // [B] Pattern(cid:104)Object(cid:105) triple=pair(x,pair(y,pair(z,isEmpty))); // [T,C,P,b] if (triple.match(list1)) // [S] succeed(x.getValue(),y.getValue(),z.getValue()); // [R,B] else // [S] fail(); // [R] Figure2: Constructionofalist(top)anditsinverseoperationwithplainJava(center)andPaisley(bottom). Forcommentsseetext. mandatedbyna¨ıvedirectuseofthedatamodelAPI,andprevalentinpractice,thatisbothinteachingand industry,isdeficientinseveralways: • Itislow-levelandoflittledocumentationvalueregardingtheintentionsoftheprogrammer. • Itlackscompositionality;althoughthecodestructureisrepetitive,itsfragmentscannotbeeasily reused,norinspected,understood,analyzed,testedanddebuggedindependently. • Itssheerverbosityleavesampleroomforcontrolanddataflowerrors. • Itentanglesconcernsthatshould,andcan,beseparated. Tranco´nyWidemann&Lepper 153 Inordertoillustratethelastpoint,wehaveannotatedeachlineofcodewiththerespectiveoperational concern: type and predicate testing [T], type casting [C], binding of variables of interest [B] and of temporary variables [b], projection to subelements [P], success management [S], and finally actual reaction[R].ThedesignofPaisleyisfoundedonanobject-orientedmodelandAPIthatseparatesthese concerns,andreifiestheirinstancesasfirst-classcitizens,asorthogonallyaspossible. ThefollowingexpositionisasummaryofthecorelayerofPaisley,asfarasrequiredforappreciation of the novel contributions discussed in the remainder of this paper. They are presented in synopsis in Figure3. Thecore-levelclassandmethodnamesareprintedinslantedfont,todistinguishthemfrom host-levelanduser-levelitems. Notethattheuseofgenerictypeshasbeensimplifiedforthesakeofeasy reading. Formoredetailssee[6]. PatternsthatpotentiallymatchtargetdataoftypeAareinstancesofclassPattern(cid:104)A(cid:105). Atthecoreof thepatternAPIisitsmethodbooleanmatch(Atarget). Thetypeparameterensuresstatictypesafety,tothe usualdegreeofJavagenerics. TheBooleanreturnvalueindicatessuccess. Puretests[T]implementmatch withoutsideeffects,eithermanuallyorbywrappingapredicateobjectwiththestaticfactorymethodtest. Therearegenericfactorymethodsfortypeandequalitytest,isInstanceOf,andeq,respectively. Localsuccessmanagement[S]isimplementedbythelogicalbinaryoperatorsand/or. Nondeterminism, suchasintroducedbyor,isimplementedbyexplicitbacktracking;afterasuccessfulinitialmatch,one may call booleanmatchAgain() to obtain further solutions, and iterate as long as successful. Note that theandcombinatorisdifferentfromtrivialsequentialmatching;itisfullydistributiveoverbacktracking, analogoustothePrologcommaoperator. Operationally,inp.and(q),qis(re)startedaftereachsuccessful matchforp. Denotationally,thedependentsumofsolutionsisformed,whichdegeneratestotheCartesian productifqisindependentofthestateofp. Data flow is by side effects only: Its simplest form is binding [B], implemented by the subclass Variable(cid:104)A(cid:105) thatsucceedsdeterministicallyandbindsthematchedtargetdata,suchthatitcanberetrieved ifasuccessfulmatchofthecontainingpatternhasbeenperformed;otherwisetheboundvalueisundefined. Temporaryvariables[b]canoftenbeelidedbymeansofpoint-freepatterncombination. Transformative data processing, such as type casting [C] and projection [P], is implemented by contravariant lifting; a data transformation of type B→A is lifted to a pattern transformation of the oppositetypePattern(cid:104)A(cid:105)→Pattern(cid:104)B(cid:105). Forinstance,consideragettermethodAgetFoo() ofclassB. The correspondingliftingisapatternfactoryofroughlythefollowingfunctionality: Pattern(cid:104)B(cid:105) foo(Pattern(cid:104)A(cid:105) p){ returnnewPattern(cid:104)B(cid:105)(){ publicbooleanmatch(Btarget){ returnp.match(target.getFoo()); } }; } Pattern factories are again reified in Paisley as class Motif(cid:104)A,B(cid:105) with methods apply and then for applicationandcomposition,respectively,thusenablingfunction-levelpatternmetaprogramming. The contravariantliftingoperatoritselfisavailableasametafactorymethodtransform. Thefunctiontobelifted istypedwithafunctionalinterface. ThisnovelfeatureofJava8emulatesthestructuraltypeoperator(→) in Java’s nominal type system, with automatic coercion to compatible functional interfaces. Thus the precedingexamplecanbeshortenedtotheexplicitliftingofafunctionobject, Motif(cid:104)A,B(cid:105) foo=transform(f); 154 ControlforPaisley publicabstractclassPattern(cid:104)A(cid:105) { publicbooleanmatch(Atarget); publicbooleanmatchAgain(); publicPattern(cid:104)A(cid:105) and(Pattern(cid:104)A(cid:105) p); publicPattern(cid:104)A(cid:105) or(Pattern(cid:104)A(cid:105) p); } publicclassVariable(cid:104)A(cid:105) extendsPattern(cid:104)A(cid:105) { privateAvalue; publicbooleanmatch(Atarget) { value=target; returntrue; } publicbooleanmatchAgain() { returnfalse; } publicAgetValue() { returnvalue; } } publicclassMotif(cid:104)A,B(cid:105) { publicPattern(cid:104)B(cid:105) apply(Pattern(cid:104)A(cid:105) p); public (cid:104)C(cid:105) Motif(cid:104)C,B(cid:105) then(Motif(cid:104)C,A(cid:105) m); publicList(cid:104)A(cid:105) eagerBindings(Btarget); publicIterable(cid:104)A(cid:105) lazyBindings(Btarget); } //miscellaneous publicstatic (cid:104)A(cid:105) Pattern(cid:104)A(cid:105) test(Predicate(cid:104)A(cid:105) p); publicstaticPattern(cid:104)Object(cid:105) isInstanceOf(Class(cid:104)?(cid:105)... c); publicstaticPattern(cid:104)Object(cid:105) eq(Objecto); publicstatic (cid:104)A,B(cid:105) Motif(cid:104)A,B(cid:105) transform(Function(cid:104)B,A(cid:105) f); publicstatic (cid:104)A(cid:105) Motif(cid:104)A,Object(cid:105) forInstancesOf(Class(cid:104)A(cid:105) c); publicstatic (cid:104)A(cid:105) Motif(cid:104)A,A(cid:105) star(Motif(cid:104)A,A(cid:105) m); publicstatic (cid:104)A(cid:105) Motif(cid:104)A,A(cid:105) plus(Motif(cid:104)A,A(cid:105) m); Figure3: PaisleycoreAPI Tranco´nyWidemann&Lepper 155 Motif(cid:104)Object,Object(cid:105) pairCar=asPair.then(car); Motif(cid:104)Object,Object(cid:105) pairCdr=asPair.then(cdr); Motif(cid:104)Object,Object(cid:105) nthcdr=star(pairCdr); // anypaircell Motif(cid:104)Object,Object(cid:105) nth=nthcdr.then(pairCar); // anyelement Figure4: EnumerationofLISPlistelementswithPaisley wherefisamethodreference,B::getFoo,ortheequivalentlambdaexpression, (Bb) b.getFoo(),which (cid:1) arebothsignificantimprovementsinexpressivityoverthepre-Java8anonymousclassnotation: Motif(cid:104)A,B(cid:105) foo=transform(newFunction(cid:104)B,A(cid:105)() { publicAapply(Bb) { returnb.getFoo(); } }); CorrespondingtothetypetestoperatorisInstanceOf,thereisananalogouspatterntransformationfor casts,forInstancesOf. ThepatterntransformationsoftypeMotif(cid:104)A,A(cid:105) formaKleenealgebrawithoperators starandplus,whichwehaveputtogooduseforrelationalprogramming[8]. InordertoapplythePaisleyframeworktotheLISPlistdatamodelfromFigure1,patternoperatorsfor theconcreteAPIofclassPairneedtobedefined. ThismodellayerofPaisleyisextensibleandtypically user-defined; the libary provides only bindings for elementary data, such as classes from the package java.lang. Thus users are free to define their own pattern access style, and to use the functionality and idiomsofthePaisleyframeworkpragmatically,inwhateverwayappearsmostnaturalandconvenient. Furthermore,sincepatternsmerelybindtothepublicAPIofadatamodel,noprivilegedaccesstosource codeorruntimeobjectsisrequired. Thedevelopmentofpatternbindingsforadatamodelismodularly independentfromthedevelopmentofinternalsofthedatamodelitself. Figure1(right)showsacanonicalimplementationofpatternsforclassPair;individualreificationsof thetypetestandcastoperationandgettermethods,plusacomplexpatternconstructorastheinverseof thedataconstructor. ComparewithFigure1(left). Figure2(bottom)showstheuseofpatternstoexpress theanalogofFigure2(center). Aclearseparationofconcernsasthreesequentialstatementshasbeen achievedbythebasicidiomofPaisleypatternusage: 1. allocatepatternvariables; 2. constructacomplexpatterntermthathandlestesting,casting,projectionandtemporaryvariables internallyandtransparently; 3. match,managesuccess,observevariablebindingsandreact. In previous applications [7, 8] we have discussed how to further encapsulate variable allocation and binding and success management for encapsulated search over nondetermistic patterns in logic and functional–logic style, respectively. For instance, enumerating the pair cells or elements of a list nondeterministicallyisasimplematterofahandfulofrelationalpatterncombinators,asshowninFigure4. TheclassMotifsupportsconciseencapsulatedsearch,exposedincollectionoriteratorstyle,viamethods eagerBindingsorlazyBindings,respectively. Forinstance,enumerateallelementsofalistasfollows: for (Objecte:nth.lazyBindings(list)) processElement(e); 156 ControlforPaisley publicclassPattern(cid:104)A(cid:105) { ... publicPattern(cid:104)A(cid:105) andThen(Runnabler); publicPattern(cid:104)A(cid:105) orElse(Runnabler); } publicstatic (cid:104)A(cid:105) booleantestThen(Atarget,Pattern(cid:104)A(cid:105) pat,Runnabler) { returnpat.andThen(r).match(target); } publicstaticbooleanotherwise(Runnabler) { r.run(); returntrue; } publicstaticvoidensure(booleansuccess) { if (!success) thrownewMatchException(); } Figure5: ContinuationextensionsincorePaisley Inthenextsectionweproposeageneral,concise,structuredimperativeusagestyle,appropriatefor situationswheremorefine-grainedinterleavingofpattern-levelanduser-levelcodeisrequired. 3 Control for Paisley ThetechnicalcontributionofthepresentpaperisanextensionofthePaisleyframework,withthepurpose of integrating pattern-based control flow – case distinctions where clauses are selected not by plain Booleanconditionsbutratherbypatterns,suchthatvariablebindingsmayoccurasasideeffectandresult indataflowtotheselectedclause. OursolutionistruetothePaisleyprinciplethatobject-orientedprogrammersshouldbegivendeclara- tiveexpressivitywithoutdeprivingthemofoperationalintuition. Thus,werequireacleanseparationof concepts,totheeffectthatanythingthatlookslikeordinarycontrolflowofthehostlanguageactually behavesassuch,andthattheentanglementofcontrolanddataflowthatisspecifictopatternmatchingis encapsulatedandabstractedappropriately. Wefindtheidealtoolforthejobinarecentmajoradditionto theJavalanguage,namelylambdaexpressions. Consideramorecomplexvariationofthedataqueryexampletaskfromtheprecedingsection,namely tosucceedforanylist,anddistinguishthefourcasesofzero,one,two,andthree-or-moreelements. Of course,patternconstructsinanalogytoFigure2(bottom)canbeusedforeachcaseindependently. Butthe resultingcodewouldbestaticallyanddynamicallyredundant,becausethecommonmatchingeffortisnot sharedbetweencases. Thesolutionistointerleaveuser-levelsuccessmanagementcodewithpattern-level testingandprojectioncode,inanestedfashionateachlevelofpair. ConsiderFigure6(left)aheadforourproposedsolutionstyle. ThePaisleybindingforthedatamodel is extended by adding a functional interface representing the continuation transform of the data class Tranco´nyWidemann&Lepper 157 Pair(top). ThenacomplexclauseoperatorpairThen,alongthelinesofFigure2,whichhandlesdataflow andmatchexecutioninternally,canbedefined(center). Itsfunctionistocallthecontinuationintheevent ofsuccess,withthedatasubitemsobtainedviapatternvariablebindings. Thesuccessflagisreturnedfor externalcascadingmanagement. Thisyieldsanidiomforpattern-basedclauses,withBooleanexpressions oftheform pairThen(list, (car,cdr) {...}) (cid:1) wherethebodyofthelambdaexpressionthatinstantiatesthecontinuationinterfaceisexecutedasaside effect,ifandonlyifthequeryfindsthattheinverseoftheconstruction list=newPair(car,cdr) applies. Additionally,theBooleanexpressioncanbewrappedinapatternbymeansofthetestfactory (bottom),forimmediateuse pair((car,cdr) {...}).match(list) (cid:1) orcompositionalembedding. Theresultingstyleisconciseandelegant;dataflowsdirectlytowell-scoped variables car and cdr, without need to allocate pattern variables and reason dynamically about their definedness. Specificcontinuations,clauseoperatorsandpatternwrappersareuser-levelconstructsspecifictoa datamodel. Fortheiruse,onlysmallextensionstothePaisleycorelevelarerequired;seeFigure5. We addpatternmethodsandThenandorElsetoaffixaparameterlesscontinuation,offunctionalinterfacetype Runnable,inthelogicallyobviousway. ThegenericclauseoperatortestThencorrespondstothewrapped formandThen. Auxiliarymethodsotherwiseandensureconvertbetweenbooleanexpressionsandvoid continuations,respectively,tocompensateforthelackofimplicitcoercionsinJava. Figure 7 explores the space of expressivity of the contination-based notation. There are two inde- pendentdegreesoffreedom,namelytheJava-levelchoiceofconditionalstatementsversusconditional operators,andthePaisley-levelchoiceofBooleanclauseexpressionsversuswrappedpatternapplications. Thusweobtainedasynopsisoffourdifferentlystyledbutstructurallyequivalentsolutionstotheproblem posedabove. Wefeelthatneitherofthesestylestakesnaturalprecedence,andleavethechoicetothetaste andconvenienceoftheuser. If only the success of a pattern matters, but no data flow of extracted subitems is required, then a simplifiedqueryimplementationwithparameterlesscontinuationssuffices. Thecorrespondingoperators aredepictedinFigure6(right). NotethatthebodyofpairThenisdefinedverboselyonlyforthesakeof synopticcomparison;itcanbeconstructedmoreconciselyinasingleexpression: testThen(target,isPair,r) Omittingunneccessarycontinuationparametersisbeneficialwithrespectbothtochoiceofefficient implementationandtotemporaryvariablehygiene. 4 Case Study WehaveappliedthePaisleystyleingeneral,andthecontrolflownotationpresentedintheprevioussection inparticular,toareal-world,pre-existing,open-sourceJavaproject. WehavechosentheKawa2.1[2] implementationoftheSchemelanguage,aGNUsoftwarepackage,forthispurpose. Therationaleisthat complexqueriesofasimpledatamodel,namelytheLISPlistsintroducedastherunningexampleabove, isapervasivetopicinSchemeimplementations. 158 ControlforPaisley interfacePairContinuation{ interfaceRunnable{ // packagejava.lang voidcont(Objectcar,Objectcdr); voidrun(); } } staticbooleanpairThen(Objecttarget, staticbooleanpairThen(Objecttarget, PairContinuationpc) { Runnabler) { Variable(cid:104)Object(cid:105) car=newVariable(cid:104)(cid:105)(), cdr=newVariable(cid:104)(cid:105)(); if (pair(car,cdr).match(target)) { if (isPair.match(target)) { pc.cont(car.getValue(),cdr.getValue()); r.run(); returntrue; returntrue; } } else else returnfalse; returnfalse; } } staticPattern(cid:104)Object(cid:105) pair(PairContinuationpc) { staticPattern(cid:104)Object(cid:105) pair(Runnabler) { returntest(x pairThen(x,pc)); returntest(x pairThen(x,r)); (cid:1) (cid:1) } } Figure6: LISPlistcontinuations(top),clauseoperators(center)andpatternwrappers(bottom);withdata flow(left)andwithout(right) if (pairThen(list1, (x,list2) { if (pair((x,list2) { (cid:1) (cid:1) if (pairThen(list2, (y,list3) { if (pair((y,list3) { (cid:1) (cid:1) if (pairThen(list3, (z,list4) { if (pair((z,list4) { (cid:1) (cid:1) case3orMore(x,y,z); case3orMore(x,y,z); })); }).match(list3)); elsecase2(x,y); elsecase2(x,y); })); }).match(list2)); elsecase1(x); elsecase1(x); })); }).match(list1)); elsecase0(); elsecase0(); pairThen(list1, (x,list2) ensure( pair((x,list2) (cid:1) (cid:1) pairThen(list2, (y,list3) ensure( pair((y,list3) (cid:1) (cid:1) pairThen(list3, (z,list4) pair((z,list4) (cid:1) (cid:1) case3orMore(x,y,z)) case3orMore(x,y,z) ||otherwise(() case2(x,y)))) ).orElse(() case2(x,y)).match(list3) (cid:1) (cid:1) ||otherwise(() case1(x)))) ).orElse(() case1(x)).match(list2) (cid:1) (cid:1) ||otherwise(() case0()) ).orElse(() case0()).match(list1) (cid:1) (cid:1) Figure7: Stylesofcomplexlistdeconstructionwithcontinuationsandconditionalstatements–withclause operators(left)andpatternwrappers(right);asconditionalstatements(top)andexpressions(bottom) Tranco´nyWidemann&Lepper 159 staticPattern(cid:104)Object(cid:105) triple(Pattern(cid:104)Object(cid:105) x,Pattern(cid:104)Object(cid:105) y,Pattern(cid:104)Object(cid:105) z) { returnpair(x,pair(y,pair(z,isEmpty))); // cf.Figure2 } staticPattern(cid:104)Object(cid:105) singleton(Pattern(cid:104)Object(cid:105) x) { returnpair(x,isEmpty); } staticbooleansingletonThen(Objecttarget,Runnabler) { returntestThen(target,pair(any,isEmpty),r); } Figure8: Advancedlistclausevocabulary Sincewearecurrentlyinterestedinqualitativeevaluation,wehavenotattemptedafullreengineering of the Kawa code. Instead, we have exploited the properties of Paisley as a lightweight embedded domain-specificlanguage,thatcanbeusedlocallywithoutimpactontheglobalstructureofaprogram, andexperimentedwithselectedfragmentsthatexhibittypicalprogrammingstyleillustratively. Figures 9, 10 and 11 (left) each show a code fragment from a source file in kawa/standard/. Reactioncodehasbeenomitted,indicatedby ... markers. Theexamplescorroboratethatourdepiction ofthena¨ıve,genuinelyobject-orientedquerystyleinFigure2isnotaparodybutstandardpractice. The variousconcernsareentangledinawaythatishighlynon-compositionalandobscurestheprogrammer’s intentions, hence the need for a comment. A notable and typical idiom in this style of imperative programmingisthereuseoftemporaryreferencevariablesinqueries,andtheirassignmentasasideeffect inthemidstofexpressions. Weregardtheidiomasintenselyobfuscatedanderror-prone. The right side of each Figure shows the respective equivalent Paisley code. We have aligned all codeverticallytohighlightthestucturalcorrespondenceasfaraspossible,ratherthanfollowthenatural structure of complex Paisley expressions by themselves. Because matching for one-element lists is a recurringthemeinFigures10and11, weaddacorrespondingclauseoperatorandpatternwrapperto themodel-specificlibrary; seeFigure8. Thissimpleexpedientresultsinconsiderablecodereuseand simplification. Wetrustthatthedirectcomparisonspeaksforitselfregardingsimplicity,compositionalityandclarity, butnameafewpointsofparticularinterest: • Recurring patterns can be named mnemonically, simultaneously increasing the reuse and the intentionaldocumentationvalueofcode,anddecreasingtheroomforerrors. • LevelsofPaisleyabstractioncanbemixed;forinstance,thelowerthirdofFigure10showsaweird querywithdoublynegatedcontinuation,nestedwithinaperfectlyregularencapsulatedsearch. • Figure11demonstratesthat(re)assignmentoftemporaryvariablescanbeabstractedaway,thus achievingfullreferentialtransparency,evenforcomplexcode. Apartfromthequalitativeandstylisticcomparison,wehaveinvestigatedsimplequantitativecriteria; seeTable1. Foreachexample,wecomparetheoriginalandthepaisleyfiedversionwithrespecttothree codemetrics: 1. Thenumberoflinesofcodepertainingtomatchingtasks. Reactioncodeandcontextareignored forthispurpose. NotethatwehavemarkedsomelinesofthePaisleyversionwith//∗,toindicate that the line break is solely due to alignment with the more verbose original version, and hence discounted.

See more

The list of books you might like

Most books are stored in the elastic cloud where traffic is expensive. For this reason, we have a limit on daily download.