Table Of ContentA Practical Study of Control in
Objected-Oriented–Functional–Logic Programming with
Paisley
BaltasarTranco´nyWidemann MarkusLepper
IlmenauUniversityofTechnology,DE <semantics/>GmbH,DE
baltasar.trancon@tu-ilmenau.de
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.