introduction to programming in atsats-lang.sourceforge.net/document/int2proginats/... · parametric...

363

Upload: doanquynh

Post on 28-Jul-2018

231 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 2: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

IntroductiontoProgramminginATSHongweiXi

ATSTrustfulSoftware,Inc.

Copyright©2010-201?HongweiXi

As a programming language, ATS is both syntax-rich and feature-rich. This book introduces thereader to some core features of ATS, including basic functional programming, simple types,(recursivelydefined)datatypes,polymorphic types,dependent types, linear types, theorem-proving,programmingwiththeorem-proving(PwTP),andtemplate-basedprogramming.Althoughthereaderisnotassumedtobefamiliarwithprogrammingingeneral,thebookislikelytoberatherdenseforsomeonewithoutconsiderableprogrammingexperience.

Allrightsarereserved.Permissionisgrantedtoprintthisdocumentforpersonaluse.

Page 3: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

DedicationToJinning,Zoe,andChloe.

TableofContentsPrefaceI.BasicFunctionalProgramming

1.PreparationforStartingARunningProgramATemplateforSingle-FileProgramsAMakefileTemplate

2.ElementsofProgrammingExpressionsandValuesNamesandBindingsScopesforBindingsEnvironmentsforEvaluationStaticSemanticsPrimitiveTypesTuplesandTupleTypesRecordsandRecordTypesConditionalExpressionsSequenceExpressionsCommentsinCode

3.FunctionsFunctionsasaSimpleFormofAbstractionFunctionArityFunctionInterfaceEvaluationofFunctionCallsRecursiveFunctionsEvaluationofRecursiveFunctionCallsExample:CoinChangesforFunTail-CallandTail-RecursionExample:TheEight-QueensPuzzleMutuallyRecursiveFunctionsMutuallyDefinedTail-RecursionEnvlessFunctionsandClosure-Functions

Page 4: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Higher-OrderFunctionsExample:BinarySearchforFunExample:AHigher-OrderFunPuzzleCurryingandUncurrying

4.DatatypesPatternsPattern-MatchingMatchingClausesandCase-ExpressionsEnumerativeDatatypesRecursivelyDefinedDatatypesExhaustivenessofPattern-MatchingExample:BinarySearchTreeExample:EvaluatingIntegerExpressions

5.ParametricPolymorphismFunctionTemplatesPolymorphicFunctionsPolymorphicDatatypesExample:FunctionTemplatesonListsExample:MergesortonLists

II.SupportforPracticalProgramming6.EffectfulProgrammingFeatures

ExceptionsExample:TestingforBraunTreesReferencesExample:ACounterImplementationArraysExample:OrderingPermutationsMatricesExample:EstimatingtheConstantPiSimpleInputandOutput

7.ModularityTypesasaFormofSpecificationStaticandDynamicATSFilesGenericTemplateImplementationSpecificTemplateImplementationAbstractTypes

Page 5: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:APackageforRationalsExample:AFunctorialPackageforRationals

8.InteractionwithCExternalGlobalNamesExternalTypesandValuesinATSInclusionofExternalCodeinATSCallingExternalFunctionsinATSUnsafeC-styleProgramminginATSExportingTypesinATSforUseinCExample:ConstructingaStaticallyAllocatedList

III.ProgrammingwithDependentTypes9.IntroductiontoDependentTypes

EnhancedExpressivenessforSpecificationConstraint-SolvingduringTypecheckingExample:StringProcessingExample:BinarySearchonArraysTermination-CheckingforRecursiveFunctionsExample:DependentTypesforDebugging

10.DatatypeRefinementDependentDatatypesExample:FunctionTemplatesonLists(Redux)Example:MergesortonLists(Redux)SequentialityofPatternMatchingExample:FunctionalRed-BlackTrees

11.Theorem-ProvinginATS/LFEncodingRelationsasDatapropsConstructingProofsasTotalFunctionsExample:DistributivityofMultiplicationExample:CommutativityofMultiplicationAlgebraicDatasortsExample:EstablishingPropertiesonBraunTreesProgrammer-CentricTheorem-Proving

12.ProgrammingwithTheorem-ProvingCircumventingNonlinearConstraintsExample:SafeMatrixSubscriptingSpecifyingwithEnhancedPrecision

Page 6: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:AnotherVerifiedFactorialExample:VerifiedFastExponentiation

IV.ProgrammingwithViewsandViewtypes13.IntroductiontoViewsandViewtypes

ViewsforMemoryAccessthroughPointersViewtypesasaCombinationofViewsandTypesLeft-ValuesandCall-by-ReferenceStack-AllocatedVariablesHeap-AllocatedLinearClosure-Functions

14.DataviewsasLinearDatapropsOptionalViewsDisjunctiveViewsDataviewforLinearArraysDataviewforLinearStringsDataviewforSingly-LinkedListsProofFunctionsforView-Changes

15.DataviewtypesasLinearDatatypesLinearOptionalValuesLinearListsExample:Merge-SortonLinearListsExample:InsertionSortonLinearListsExample:Quick-SortonLinearListsLinearBinarySearchTreesTransitionfromDatatypestoDataviewtypes

16.AbstractViewsandViewtypesSimpleLinearObjectsMemoryAllocationandDeallocationExample:Array-BasedCircularBuffersLockingandUnlockingLinearChannelsforAsynchronousIPC

V.ProgrammingwithFunctionTemplates17.FromGenericitytoLate-Binding

GenericityofTemplateImplementationsExample:GenericOperationsonNumbersTemplatesasaSpecialFormofFunctorsExample:TemplatesforLoopConstruction

Page 7: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Template-BasedSupportforLate-Binding

Page 8: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

PrefaceATS is a statically typed programming language that unifies implementation with formalspecification. Within ATS, there are two sublanguages: one for specification and the other forimplementation, and there is also a theorem-proving subsystem for verifying whether animplementationindeedimplementsaccordingtoitsspecification.IfIcouldassociateonlyonesinglewordwithATS,Iwouldchoosethewordprecision.ProgramminginATSisaboutbeingpreciseandbeingabletoeffectivelyenforceprecision.Thispointwillbedemonstratedconcretelyandrepeatedlyinthisbook.

Inordertobepreciseinbuildingsoftwaresystems,weneedtospecifywhatsuchasystemisexpectedtoaccomplish.Inthecurrentdayandage,softwarespecification,whichisusedinaratherloosesensehere, isoftendone in formsofvaryingdegreesof formalism, ranging fromverbaldiscussions topencil/paper drawings to diagrammatic depictions in modeling languages such as UML to textdescriptions in formal specification languages such as VDM and Z. Often the main purpose ofsoftwarespecificationistoestablishsomemutualunderstandingamongateamofdevelopers.Afterthespecificationforasoftwaresystemisdone,eitherformallyorinformally,weneedtoimplementthespecificationinaprogramminglanguage.Ingeneral,itisexceedinglydifficulttobereasonablycertain whether an implementation actually meets its specification. Even if the implementationcohereswellwithitsspecificationinitially,itnearlyinevitablydivergesfromthespecificationasthesoftware systemevolves.Thedreadful consequencesof suchadivergenceare all too familiar; thespecificationbecomes less and less reliable for understanding thebehavior of the software systemwhile the implementationgradually turns into itsownspecification; for thedevelopers, itbecomesincreasinglydifficultandriskytomaintainandextendthesoftwaresystem;fortheusers,itrequiresincreasedamountoftimeandefforttolearnandusethesoftwaresystem.

Largely inspiredbyMartin-Loef'sconstructive type theory,whichwasoriginallydevelopedfor thepurpose of establishing a foundation for mathematics, I designed ATS in an attempt to combinespecificationandimplementationintoasingleprogramminglanguage.Thereareastaticcomponent(statics)andadynamiccomponent(dynamics)inATS.Intuitively, thestaticsanddynamicsareeachforhandlingtypesandprograms,respectively.Inparticular,specificationisdoneinthestatics.Givenaspecification,howcanwetheneffectivelyensurethatanimplementationofthespecification(type)indeed implements according to the specification?We request that the programmer who does theimplementationalsoconstructaproof in the theorem-provingsubsystemofATS todemonstrate it.Thisisastyleofprogramverificationthatputstheprogrammeratthecenter,andthuswerefertoitasaprogrammer-centricapproachtoprogramverification.

Page 9: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

As a programming language,ATS is both syntax-rich and feature-rich. It can support a variety ofprogramming paradigms, including functional programming, imperative programming, object-orientedprogramming,concurrentprogramming,modularprogramming,etc.However,thecoreofATS,whichisbasedonacall-by-valuefunctionallanguage,issurprisinglysimple,andthisiswherethe journey of programming in ATS starts. In this book, I will demonstrate primarily throughexamples how various programming features inATS can be employed effectively to facilitate theconstruction of high-quality programs. I will focus on programming practice instead ofprogrammingtheory.Ifyouareprimarilyinterestedinthetype-theoreticalfoundationofATS,thenyouhavetofinditelsewhere.

If youcan implement, thenyouare agoodprogrammer. In order to be a better programmer, youshouldalsobeabletoexplainwhatyouimplement.Ifyoucanguaranteewhatisimplementedmatcheswhatisspecified,thenyouaresurelythebestprogrammer.Hopefully,learningATSwillputyouonawonderfulexploringjourneytobecomethebestprogrammer.Letthatjourneystartnow!

Page 10: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

I.BasicFunctionalProgrammingTableofContents1.PreparationforStarting2.ElementsofProgramming3.Functions4.Datatypes5.ParametricPolymorphism

Page 11: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 12: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 13: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter1.PreparationforStartingItislikelythatyouwanttowriteprogramsintheprogramminglanguageyouarelearning.Youmayalsowanttotrysomeoftheexamplesincludedinthisbookandseewhatreallyhappens.SoIwillfirstshowyouhowtowriteinATSasingle-fileprogram,thatis,aprogramcontainedinasinglefile,andcompileitandthenexecuteit.

Page 14: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ARunningProgram

The following example is a program in ATS that prints out (onto the console) the string "Hello,world!"plusanewlinebeforeitterminates:

val_=print("Hello,world!\n")

implementmain0()=()//adummyfor[main]

Thekeyword val initiatesabindingbetweenthevariable _ (underscore)andthefunctioncall print("Hello,world!\n") .However,thisbindingisneverusedafteritisintroduced;itssolepurposeisforthecalltothe print functiontogetevaluated.

The function main0 is a slight variant of another function named main ,which is of certain specialmeaninginATS.ForaprogrammerwhoknowstheCorJavaprogramminglanguage,Isimplypointoutthattheroleof main isessentiallythesameasitscounterpartofthesamenameinCorJava.Thekeyword implement initiates the implementation of a function whose interface has already beendeclaredelsewhere.Followingisthedeclaredinterfacefor main0 inATS:

funmain0():void

whichindicatesthat main0 isanullaryfunction,thatis,afunctiontakingnoarguments,anditreturnsno value (or it returns the void value). The double slash symbol ( // ) initiates a comment thatterminatesattheendofthecurrentline.

Suppose thatyouhavealready installed theATSprogramming language system.Youcan issue thefollowingcommand-linetogenerateanexecutablenamedhellointhecurrentworkingdirectory:

atscc-ohellohello.dats

wherehello.datsreferstoafilecontainingtheaboveprogram.Thecommandatsccisessentiallya

conveniencewrapperaround thecommandatsopt,which triggers theprocessof typecheckingandcompilingATSprograms.Note thatatsccandatsoptmayactuallybegiven thenamespatscc andpatsopt, respectively, in certain installations of ATS. The filename extension .dats should not bealtered as it has already been assigned a special meaning that the compilation command atsccrecognizes.Anotherspecialfilenameextensionis.sats,whichwewillsoonencounter.

Page 15: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ATemplateforSingle-FilePrograms

The followingcode template,which is availableon-line, is designed for constructing a single-fileprograminATS:

(*

**

**Atemplateforsingle-fileATSprograms

**

*)

(**************)

//

#include"share/atspre_define.hats"

#include"share/atspre_staload.hats"

//

(**************)

//

//pleasewriteyouprograminthissection

//

(**************)

implementmain0()=()//adummyimplementationfor[main]

Thelinestartingwiththekeyword #include enablestheATScompileratsopttogainaccesstocertainexternal librarypackagesand thedefinitionsofvarious libraryfunctions. Iwillcoverelsewhere inthebookthetopiconmakinguseoflibrarycodeinATS.

Page 16: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

AMakefileTemplate

ThefollowingMakefiletemplate,whichisavailableon-line,isprovidedtohelpyouconstructyourownMakefileforcompilingATSprograms.Ifyouarenotfamiliarwiththemakeutility,youcouldreadilyfindplentyresourceson-linetohelpyourselflearnit.

######

#

#Notethat

#certaininstallationsrequirethefollowingchanges:

#

#atscc->patscc

#atsopt->patsopt

#ATSHOME->PATSHOME

#

######

ATSHOMEQ="$(ATSHOME)"

######

ATSCC=$(ATSHOMEQ)/bin/atscc

ATSOPT=$(ATSHOMEQ)/bin/atsopt

######

#

#HX:Pleaseuncommenttheoneyouwant,orskipitentirely

#

ATSCCFLAGS=

#ATSCCFLAGS=-O2

#

#'-flto'enableslink-timeoptimizationsuchasinlininglibfunctions

#

#ATSCCFLAGS=-O2-flto

#

######

cleanall::

######

#

#Pleaseuncommentthefollowingthreelinesandreplacethename[foo]

Page 17: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

#withthenameofthefileyouwanttocompile

#

#foo:foo.dats;\

#$(ATSCC)$(ATSCCFLAGS)-o$@$<||echo$@":ERROR!!!"

#cleanall::;$(RMF)foo

######

#

#Youmayfindtheserulesuseful

#

#%_sats.o:%.sats;$(ATSCC)$(ATSCCFLAGS)-c$<||echo$@":ERROR!!!"

#%_dats.o:%.dats;$(ATSCC)$(ATSCCFLAGS)-c$<||echo$@":ERROR!!!"

######

RMF=rm-f

######

clean::;$(RMF)*~

clean::;$(RMF)*_?ats.o

clean::;$(RMF)*_?ats.c

cleanall::clean

######endof[Makefile]######

Page 18: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 19: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 20: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter2.ElementsofProgrammingThecoreofATSisacall-by-valuefunctionalprogramminglanguage.Iwillexplainthemeaningofcall-by-valueinamoment.Asforfunctionalprogramming,thereisreallynoprecisedefinition.Themost important aspect of functional programming that Iwant to explore is the notion of binding,whichrelatesnamestoexpressions.

Page 21: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ExpressionsandValues

ATS is both syntax-rich and feature-rich, and its grammar is probably more complex than mostexistingprogramminglanguages.InATS,therearealargevarietyofformsofexpressions,whichIwillintroducegradually.

Letusfirststartwithsomeintegerarithmeticexpressions(IAEs): 1 , ~2 , 1+2 , 1+2*3-4 , (1+2)/(3-4) ,etc.Notethatthenegativesignisrepresentedbythetildesymbol( ~ )inATS.Thereisalsosupportforfloatingpointnumbers,andsomefloatingpointconstantsaregivenhere: 1.0 , ~2.0 , 3. , 0.12345 ,2.71828 , 31416E-4 ,etc.Notethat 3. and 31416E-4 arethesameas 3.0 and 3.1416 ,respectively.WhatIreallywanttoemphasizeatthispointisthat 1 and 1.0 aretwodistinctnumbersinATS:theformerisanintegerwhilethelatterisafloatingpointnumber(ofdoubleprecision).

Therearealsobooleanconstants: true and false .Wecanformbooleanexpressionssuchas 1>=0 ,not(2-1>=2) , (1<2)andalso(2<3) and (~1>1)orelse(~1<=1) ,where not , andalso and orelsestandfornegation,conjunctionanddisjunction,respectively.ForprogrammersfamiliarwithC-likesyntax,Ipointoutthatoperators && and || aresynonymsfor andalso and orelse ,respectively.

Other commonly used constant values include characters and strings. For instance, following aresomecharacter constants: 'a' , 'B' , '\n' (newline), '\t' (tab), '\(' (left parenthesis), ')' (rightparenthesis), '\{' (leftcurlybrace), '}' (rightcurlybrace),etc;followingaresomestringconstants:"MynameisZoe" , "Don'tcallme\"Chloe\"" , "thisisanewline:\n" ,etc.

Given a (function) name, say, foo, and an expression exp, the expression foo(exp) is a functionapplicationorfunctioncall.Theparenthesesinfoo(exp)maybedroppedifnoambiguityiscreatedbydoingso.Forinstance, print("Hello") isafunctionapplication,whichcanalsobewrittenas print"Hello" .Iffooisanullaryfunction,thenafunctionapplicationfoo()canbeformed.Iffooisabinaryfunction,thenafunctionapplicationfoo(exp1,exp2)canbeformedforexpressionsexp1andexp2.Functionsofmoreargumentscanbetreatedaccordingly.

Notethatwecannotwrite +(1,2) asthename + hasalreadybeengiventheinfixstatusrequiringthatitbetreatedasaninfixoperator.However,wecanwrite op+(1,2) ,where op isakeywordinATSthatcan be used to temporarily suspend the infix status of any name immediately following it. I willexplainindetailtheissueoffixity(prefix,infixandpostfix)elsewhere.

Values are essentially expressionsof certain special forms,which cannot be reducedor simplifiedfurther.Forinstance,integerconstantssuchas 1 and ~2 arevalues,buttheintegerexpression 1+2 is

Page 22: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

notavalue,whichcanbereducedtothevalue 3 .Evaluationreferstothecomputationalprocessthatreducesagivenexpressionintoavalue.However,certainexpressionssuchas 1/0 cannotbereducedtoavalue,andevaluatingsuchanexpressionmustabortatsomepoint.Iwillgraduallypresentmoreinformationonevaluation.

Page 23: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

NamesandBindings

Acrucialaspectofaprogramminglanguageisthemechanismitprovidesforbindingnames,whicharethemselvesexpressions,toexpressions.Forinstance,adeclarationisintroducedbythefollowingsyntax thatdeclaresabindingbetween thename x ,which isalso referred toasavariable, and theexpression 1+2 :

valx=1+2

Notethat val isakeywordinATS,andthedeclarationisclassifiedasaval-declaration.Conceptually,whathappensatrun-timeinacall-by-valuelanguagesuchasATSisthattheexpression 1+2 is firstevaluatedtothevalue 3 ,andthenthebindingbetween x and 1+2 isfinalizedintoabindingbetweenx and 3 .Essentially,call-by-valuemeansthatabindingbetweenanameandanexpressionneedstobe finalized into one between the name and the value of the expression before it can be used inevaluation subsequently.As another example, the following syntax declares three bindings, two ofwhichareformedsimultaneouslyinthefirstline:

valPI=3.14andradius=10.0

valarea=PI*radius*radius

Note that it is unspecified inATSas towhichof the first twobindings (connectedby thekeywordand ) is finalized aheadof theother at run-time.However, it is guaranteed that the thirdbinding isfinalizedafterthefirsttwoaredone.Toseethisissuefromadifferentangle,wecantrytotypecheckthefollowingcode:

valx=0andy=x+1

The error message reported in this case indicates that the name (or dynamic identifier) x in theexpression x+1 isunbound.Inparticular,thetwooccurrencesof x intheabovecodeareunrelated.

Page 24: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ScopesforBindings

Eachbindingisgivenafixedscopeinwhichthebindingisconsideredlegaloreffective.Thescopeofatoplevelbindinginafilestartsfromthepointwherethebindingisintroduceduntiltheveryendofthefile.Thebindingsintroducedinthefollowingexamplebetweenthekeywords let and in areeffectiveuntilthekeyword end isreached:

valarea=let

valPI=3.14andradius=10.0inPI*radius*radius

end//endof[let]

Suchbindingsarereferredtoaslocalbindings,andthenamessuchas PI and radius arereferredtoaslocalnames.Thisexamplecanalsobewritteninthefollowingstyle:

valarea=

PI*radius*radiuswhere{

valPI=3.14andradius=10.0//simultaneousbindings

}//endof[where]//endof[val]

Thekeyword where appearing immediately after an expression introduces bindings that are solelyeffective forevaluatingnamescontained in theexpression.Note that expressions formedusing thekeywords let and where areoftenreferredtoaslet-expressionsandwhere-expressions,respectively.The formercanalwaysbe translated into the latterdirectlyandviceversa.Which style is better? Ihave not formed my opinion yet. The answer seems to entirely depend on the taste of theprogrammer.

Thefollowingexampledemonstratesanalternativeapproachtointroducinglocalbindings:

local

valPI=3.14andradius=10.0

in(*inof[local]*)

valarea=PI*radius*radius

end//endof[local]

where thebindings introducedbetween thekeywords local and in are effectiveuntil thekeywordend isreached.Notethatthebindingsintroducedbetweenthekeywords in and end are themselvestoplevelbindings.Thedifferencebetween let and local shouldbeclear:Theformerisusedtoform

Page 25: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

anexpressionwhilethelatterisusedtointroduceasequenceofdeclarations.

Page 26: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

EnvironmentsforEvaluation

Evaluation is the computational process that reduces expressions to values. When performingevaluation,weneednotonlytheexpressiontobeevaluatedbutalsoacollectionofbindingsthatmapnamesintheexpressiontovalues.Thiscollectionofbindings,whichisjustafinitemapping,isoftenreferred to as an environment (for evaluation). For instance, suppose thatwewant to evaluate thefollowingexpression:

let

valPI=3.14andradius2=10.0*10.0inPI*radius2

end

WestartwiththeemptyenvironmentENV0;weevaluate 3.14 toitselfand 10.0*10.0 to 100.0 undertheenvironmentENV0;wethenextendENV0toENV1withtwobindingsmapping PI to 3.14 andradius2 to 100.0 ;wethenevaluate PI*radius2 underENV1to 3.14*radius2 ,thento 3.14*100.0 ,andfinallyto 314.0 ,whichisthevalueofthelet-expression.

Page 27: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

StaticSemantics

ATSisaprogramminglanguageequippedwithahighlyexpressivetypesystemrootedintheAppliedTypeSystemframework,whichalsogivesATSitsname.IwillgraduallyintroducethetypesystemofATS,whichisprobablythemostoutstandingandinterestingpartofthisbook.

Itiscommontotreatatypeasthesetofvaluesitclassifies.However,Ifinditmoreapproriatetotreata typeasa formofmeaning.Thereare formal rules forassigning types toexpressions,whicharereferredtoastypingrules.IfatypeTcanbeassignedtoanexpression,thenIsaythattheexpressionpossesses thestaticmeaning (semantics) representedby the typeT.Note thatanexpressionmaybeassignedmanydistinctstaticmeanings.Anexpressioniswell-typedifthereexistsatypeTsuchthattheexpressioncanbeassignedthetypeT.

IfthereisabindingbetweenanameandanexpressionandtheexpressionisofsometypeT,thenthenameisassumedtobeofthetypeTintheeffectivescopeofthebinding.Inotherwords,thenameassumesthestaticmeaningoftheexpressionitrefersto.

Letexp0beanexpressionofsome typeT, that is, the typeTcanbeassigned toexp0according tocertain typing rules. Ifwecanevaluateexp0 toexp1, thenexp1canalsobeassigned the typeT. Inotherwords,staticmeaningisaninvariantunderevaluation.Thispropertyisoftenreferredtoastypepreservation,whichispartofthesoundnessofthetypesystemofATS.Basedonthisproperty,wecanreadilyinferthatanyvalueisofthetypeTifexp0canbeevaluatedtoit(inmultiplesteps).

Letexp0beanexpressionofsometypeT.Assumethatexp0isnotavalue.Thenexp0canalwaysbeevaluatedonestepfurthertoanotherexpressionexp1.Thispropertyisoftenreferredtoasprogress,whichisanotherpartofthesoundnessofthetypesystemofATS.

Page 28: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

PrimitiveTypes

The simplest types in ATS are primitive types, which are used to classify primitive values. Forinstance,wehavetheprimitivetypes int and double ,whichclassifyintegers(inafixedrange)andfloatingpointnumbers(ofdoubleprecision),respectively.

In thecurrent implementationofATS (Postiats), aprogram inATS is first compiled intoone inC(conforming to theC99standard),whichcan thenbecompiled toobjectcodebyacompiler forCsuchasgcc. In thecompilationfromATStoC, the type int inATSis translated to the typeof thesamenameinC.Similarly,thetype double inATSistranslatedtothetypeofthesamenameinC.

TherearemanyotherprimitivetypesinATS,andIwillintroducethemgradually.Somecommonlyusedprimitivetypesarelistedasfollows:

bool :Thistypeisforbooleanvalues true and false ,anditistranslatedintotheinttypeinC.

char :ThistypeistranslatedintothetypeinCforcharacters.

schar :ThistypeistranslatedintothetypeinCforsignedcharacters.

uchar :ThistypeistranslatedintothetypeinCforunsignedcharacters.

float :ThistypeistranslatedintothetypeinCforfloatingpointnumbersofsingleprecision.

uint :ThistypeistranslatedintothetypeinCforunsignedintegers.

lint :ThistypeistranslatedintothetypeinCforlongintegers.

ulint :ThistypeistranslatedintothetypeinCforunsignedlongintegers.

llint :ThistypeistranslatedintothetypeinCforlonglongintegers.

ullint :ThistypeistranslatedintothetypeinCforunsignedlonglongintegers.

size_t :ThistypeistranslatedintothetypeinCofthesamename,whichisforunsignedintegersofcertainprecision.Usually,thetype size_t canbetreatedasthetype ulint andviceversa.

ssize_t :ThistypeistranslatedintothetypeinCofthesamename,whichisforsignedintegersofcertainprecision.Usually,thetype ssize_t canbetreatedasthetype lint andviceversa.

Page 29: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

string :Thistypeisforstrings,anditstranslationinCisthetypeforpointers.Iwillexplainthistranslationelsewhere.

void :This type is for the void value, and its translation inC is the type of the samename. ItshouldbenotedthatthevoidvalueisunspecifiedinATS.Ioftensaythatafunctionreturnsnovalueifitreturnsthevoidvalue,andviceversa.

Iwillgraduallypresentprogrammingexamplesinvolvingvariousprimitivetypesandvalues.

Page 30: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

TuplesandTupleTypes

GiventwotypesT1andT2,wecanformatupletype(T1,T2),whichcanalsobewrittenas@(T1,T2).Assumethatexp1andexp2are twoexpressionsof the typesT1andT2,respectively.Thentheexpression(exp1,exp2),whichcanalsobewrittenas@(exp1,exp2),referstoatupleofthetupletype(T1,T2).Accordingly,wecanformtuplesandtupletypesofmorecomponents.Inorderforatupletypetobeassignedtoatuple,thetupleandthetupletypemusthavetheequalnumberofcomponents.

Whenevaluatingatupleexpression,weevaluateallofitscomponentssequentially.Supposethattheexpressioncontainsn components, then thevalueof the expression is the tuple consistingof thenvaluesofthencomponentslistedintheorderasthecomponentsthemselves.

A tupleof lengthn for n>=2 is just a recordof fieldnames ranging from0until n-1, inclusive.Givenanexpressionexpofsometupletype(T1,T2),wecanformexpressions(exp).0and(exp).1,whichareoftypesT1andT2,respectively.Notethattheexpressionexpdoesnothavetobeatupleexpression.Forinstance,expmaybeanameorafunctionapplication.Ifexpevaluatestoatupleoftwovalues,thenexp.0evaluatestothefirstvalueandexp.1thesecondvalue.Clearly,ifthetupletypeofexpcontainsmorecomponents,whatisstatedcanbegeneralizedaccordingly.

Inthefollowingexample,wefirstconstructatupleoflength3andthenintroducebindingsbetween3namesandallofthe3componentsofthetuple:

valxyz=('A',1,2.0)

valx=xyz.0andy=xyz.1andz=xyz.2

Notethattheconstructedtuplecanbeassignedthetupletype (char,int,double) .Anothermethodforselecting components in a given tuple is based on pattern matching, which is employed in thefollowingexample:

valxyz=('A',1,2.0)

val(x,y,z)=xyz//x='A';y=1;z=2.0

Notethat (x,y,z) isapatternthatcanmatchanytuplesofexact3components.Iwillsaymoreaboutpatternmatchingelsewhere.

Thetuplesintroducedaboveareoftenreferredtoasflattuples,nativetuplesorunboxedtuples.ThereisanotherkindoftuplessupportedinATS,whicharecalledboxedtuples.Aboxedtupleisessentiallyapointerpointingtosomeheaplocationwhereaflattupleisstored.

Page 31: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Assume that exp1 and exp2 are two expressions of the types T1 and T2, respectively. Then theexpression'(exp1,exp2),referstoatupleofthetupletype'(T1,T2).Accordingly,wecanformboxedtuplesandboxedtupletypesoffewerormorecomponents.Whatshouldbenotedimmediatelyisthateveryboxedtupleisofthesizeofapointer,andcanthusbestoredinanyplacewhereapointercan.Using boxed tuples is rather similar to using unboxed ones. For instance, the meaning of thefollowingcodeshouldbeevident:

valxyz='('A',1,2.0)

valx=xyz.0andy=xyz.1andz=xyz.2

Notethataspaceisneededbetween '( and 'A' forotherwisethecurrentparser(forATS/Postiats)wouldbeconfused.

Giventheavailabilityofflatandboxedtuples,onenaturallywantstoknowwhetherthereisasimplewaytodeterminewhichkindispreferredovertheother.Unfortunately,thereisnosimplewaytodothisasfarasIcantell.Inordertobecertain,somekindofprofilingisoftenneeded.However,ifwewanttoruncodewithnosupportofgarbagecollection(GC),thenweshoulddefinitelyavoidusingboxedtuples.

Page 32: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

RecordsandRecordTypes

Arecordisjustlikeatupleexceptthateachfieldnameoftherecordischosenbytheprogrammer(insteadofbeingfixed).Similarly,arecordtypeisjustlikeatupletype.Forinstance,arecordtypepoint2D isdefinedasfollows:

typedefpoint2D=@{x=double,y=double}

where x and y arethenamesofthetwofieldsinarecordvalueofthistype.Wealsorefertoafieldin a record as a component. The special symbol @{ indicates that the formed type is forflat/native/unboxedrecords.Avalueofthetype point2D isconstructedasfollowsandgiventhenametheOrigin :

valtheOrigin=@{x=0.0,y=0.0}:point2D

Wecanusethestandarddotnotationtoextractoutaselectedcomponentinarecord,andthisisshowninthenextlineofcode:

valtheOrigin_x=theOrigin.xandtheOrigin_y=theOrigin.y

Alternatively,wecanusepatternmatchingfordoingcomponentextractionasisdoneinthenextlineofcode:

val@{x=theOrigin_x,y=theOrigin_y}=theOrigin

Inthiscase,thenames theOrigin_x and theOrigin_y areboundtothecomponentsin theOrgin thatarenamed x and y ,respectively.Ifweonlyneedtoextractoutaselectedfewofcomponents(insteadofalltheavailableones),wecanmakeuseofthefollowingkindofpatterns:

val@{x=theOrigin_x,...}=theOrigin//thex-componentonly

val@{y=theOrigin_y,...}=theOrigin//they-componentonly

Ifyoufindallthissyntaxforcomponentextractiontobeconfusing,thenIsuggestthatyousticktothedotnotation.Imyselfrarelyusepatternmatchingonrecordvalues.

Compared with handling native/flat/unboxed records, the only change needed for handling boxedrecords is to replace the special symbol @{ with another one: '{ , which is a quote followedimmediatelybyaleftcurlybrace.

Page 33: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ConditionalExpressions

Aconditionalexpressionconsistsofatestandtwobranches.Forinstance,thefollowingexpressionisconditional:

if(x>=0)thenxelse~x

where if , then and else arekeywordsinATS.Inaconditionalexpression,theexpressionfollowingif isthetestandtheexpressionsfollowing then and else arereferredtoasthethen-branchandtheelse-branch(oftheconditionalexpression),respectively.

InordertoassignatypeTtoaconditionalexpression,weneedtoassignthetype bool tothetestandthetypeTtobothofthethen-branchandtheelse-branch.Forinstance,thetype int canbeassignedtotheaboveconditionalexpressionifthename x isgiventhetype int .

Supposethatwehaveaconditionalexpressionthatiswell-typed.Whenevaluatingit,wefirstevaluatethe test to a value, which is guaranteed to be either true or false ; if the value is true , then wecontinuetoevaluatethethen-branch;otherwise,wecontinuetoevaluatetheelse-branch.

Itisalsoallowedtoformaconditionalexpressionwheretheelse-branchismissingortruncated.Forinstance,wecanformanexpressionasfollows:

if(x>=0)thenprint(x)

whichisequivalenttothefollowingconditionalexpression:

if(x>=0)thenprint(x)else()

Notethat () standsfor thevoidvalue(of the type void ). Ifa typecanbeassignedtoaconditionalexpressioninthetruncatedform,thenthetypemustbe void .

Page 34: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

SequenceExpressions

Assumethatexp1andexp2areexpressionsoftypesT1andT2respectively,whereT1is void .Thenasequenceexpression(exp1;exp2)canbeformedthatisofthetypeT2.Whenevaluatingthesequenceexpression (exp1; exp2), we first evaluate exp1 to the void value and then evaluate exp2 to somevalue,whichisalsothevalueofthesequenceexpression.Whenmoreexpressionsaresequenced,allofthembutthelastoneneedtobeofthetype void andthetypeofthelastexpressionisalsothetypeofthesequenceexpressionbeingformed.Evaluatingasequenceofmoreexpressionsisanalogoustoevaluatingasequenceoftwo.Thefollowingexampleisasequenceexpression:

(print'H';print'e';print'l';print'l';print'o')

Evaluatingthissequenceexpressionprintsout(ontotheconsole)the5-letterstring"Hello".Insteadofparentheses,wecanalsousethekeywords begin and end toformasequenceexpression:

begin

print'H';print'e';print'l';print'l';print'o'

end//endof[begin]

Ifwelike,wemayalsoaddasemicolonimmediatelyafterthelastexpressioninasequenceaslongasthelastexpressionisofthetype void .Forinstance,theaboveexamplecanalsobewrittenasfollows:

begin

print'H';print'e';print'l';print'l';print'o';

end//endof[begin]

Ialsowanttopointoutthefollowingstyleofsequencing:

let

val()=print'H'

val()=print'e'

val()=print'l'

val()=print'l'

val()=print'o'

in

//nothing

end//endof[let]

whichisquitecommoninfunctionalprogramming.

Page 35: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

CommentsinCode

ATScurrentlysupportsfourformsofcomments:linecomment,blockcommentofML-style,blockcommentofC-style,andrest-of-filecomment.

Alinecommentstartswiththedoubleslashsymbol( // )andextendsuntiltheendofthecurrentline.

AblockcommentofML-stylestartsandcloseswiththetokens (* and *) ,respectively.Notethatnested block comments ofML-style are allowed, that is, one block comment ofML-style canoccurwithinanotheroneofthesamestyle.

AblockcommentofC-stylestartsandcloseswiththetokens /* and */ ,respectively.NotethatblockcommentsofC-stylecannotbenested.TheuseofblockcommentsofC-styleisprimarilyincodethatissupposedtobesharedbyATSandC.Inothercases,blockcommentsofML-styleshouldbethepreferredchoice.

Arest-of-filecommentstartswiththequadrupleslashsymbol( //// )andextendsuntiltheendofthefile.Commentsofthisstyleofareprimarilyusefulfordevelopingordebuggingprograms.

Page 36: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 37: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 38: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter3.FunctionsFunctions play a foundational role in programming. While it may be theoretically possible toprogramwithoutfunctions(butwithloops),suchaprogrammingstyleisoflittlepracticalvalue.ATSdoes provide some language constructs for implementing for-loops and while-loops directly. I,however,stronglyrecommendthattheprogrammerimplementloopsasrecursivefunctionsormoreprecisely, as tail-recursive functions. This is a programming style that matches well with moreadvancedprogrammingfeaturesinATS,whichwillbepresentedinthisbooklater.

Thecodeemployedforillustrationinthischapterplussomeadditionalcodefortestingisavailableon-line.

Page 39: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

FunctionsasaSimpleFormofAbstraction

Givenanexpressionexpofthetype double ,wecanmultiplyexpbyitselftocomputeitssquare.Ifexpis a complex expression,wemay introduce a bindingbetween a name and exp so that exp is onlyevaluatedonce.Thisideaisshowninthefollowingexample:

letvalx=3.14*(10.0-1.0/1.4142)inx*xend

Nowsupposethatwehavefoundamoreefficientwaytodosquaring.Inordertotakefulladvantageofit,weneedtomodifyeachoccurrenceofsquaringinthecurrentprogramaccordingly.Thisstyleofprogrammingisclearlynotmodular,anditisoflittlechancetoscale.Toaddressthisproblem,wecanimplementafunctionasfollowstocomputethesquareofagivenfloatingpointnumber:

fnsquare(x:double):double=x*x

Thekeyword fn initiatesthedefinitionofanon-recursivefunction,andthenamefollowingitisforthefunctiontobedefined.Intheaboveexample,thefunction square takesoneargumentofthenamex ,whichisassumedtohavethetype double ,andreturnsavalueofthetype double .Theexpressionontheright-handside(RHS)ofthesymbol = isthebodyofthefunction,whichis x*x inthiscase.Ifwehaveamoreefficientway todosquaring,wecan just re-implement thebodyof the functionsquare accordingly to take advantage of it, and there is no other changes needed (assuming thatsquaringissolelydonebycalling square ).

If square isaname,whatistheexpressionitrefersto?Itturnsoutthattheabovefunctiondefinitioncanalsobewrittenasfollows:

valsquare=lam(x:double):double=>x*x

where theRHS of the symbol = is a lambda-expression representing an anonymous function thattakes one argument of the type double and returns a value of the type double , and the expressionfollowing the symbol => is the body of the function. If wewish, we can change the name of thefunctionargumentasfollows:

valsquare=lam(y:double):double=>y*y

Thisiscalledalpha-renaming(offunctionarguments),andthenewlambda-expressionissaidtobealpha-equivalenttotheoriginalone.

Page 40: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

A lambda-expression is a (function) value. Suppose we have a lambda-expression representing abinaryfunction, that is,afunctiontakingtwoarguments.Inordertoassignatypeof theform(T1,T2)->Ttothelambda-expression,weneedtoverifythatthebodyofthefunctioncanbegiventhetypeTifthetwoargumentsofthefunctionareassumedtohavethetypesT1andT2.Whatisstatedalso applies, mutatis mutandis, to lambda-expressions representing functions of fewer or morearguments.Forinstance,thelambda-expression lam(x:double):double=>x*x canbeassignedthefunctiontype (double)->double ,whichmayalsobewrittenas double->double .

Assumethatexpisanexpressionofsomefunctiontype(T1,T2)->T.Notethatexpisnotnecessarilyanameora lambda-expression.Ifexpressionsexp1andexp2canbeassigned the typesT1andT2,thenthefunctionapplicationexp(exp1,exp2),whichmayalsobereferredtoasafunctioncall,canbeassignedthetypeT.Typingafunctionapplicationoffewerormoreargumentsishandledsimilarly.

Letusnowseeanexamplethatbuildsonthepreviouslydefinedfunction square .Theboundaryofaringconsistsoftwocirclescenteredatthesamepoint.IftheradiioftheouterandinnercirclesareRandr,respectively,thentheareaoftheringcanbecomputedbythefollowingfunction area_of_ring :

fnarea_of_ring

(R:double,r:double):double=3.1416*(square(R)-square(r))

//endof[area_of_ring]

Given that the subtraction andmultiplication functions (on floating point numbers) are of the type(double,double)->double and square isofthetype (double)->double ,itisasimpleroutinetoverifythatthebodyof area_of_ring canbeassignedthetype double .

Page 41: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

FunctionArity

Thearityofafunctionisthenumberofargumentsthefunctiontakes.Functionsofarity0,1,2and3areoftencallednullary,unary,binaryandternaryfunctions,respectively.Forexample,thefollowingfunction sqrsum1 isabinaryfunctionsuchthatitstwoargumentsareofthetype int :

fnsqrsum1(x:int,y:int):int=x*x+y*y

Wecandefineaunaryfunction sqrsum2 asfollows:

//

typedefint2=(int,int)

//

fnsqrsum2

(xy:int2):int=

letvalx=xy.0andy=xy.1inx*x+y*yend

//endof[sqrsum2]

Thekeyword typedef introducesabindingbetweenthename int2 andthetupletype (int, int) . Inotherwords, int2 istreatedasanabbreviationoraliasfor (int,int) .Thefunction sqrsum2 isunaryas it takesonlyoneargument,which isa tupleof the type int2 .Whenapplying sqrsum2 to a tupleconsistingof 1 and ~1 ,weneedtowrite sqrsum2@(1,~1) .Ifwesimplywrite sqrsum2(1,~1) , thenthetypecheckeristoreportanerroroffunctionaritymismatchasitassumesthat sqrsum2 isappliedtotwoarguments(insteadofonerepresentingapair).

Manyfunctionallanguages(e.g.,HaskellandML)onlyallowunaryfunctions.Afunctionofmultipleargumentsisencodedintheselanguagesasaunaryfunctiontakingatupleasitsonlyargumentoritis curried into a function that takes these arguments sequentially. ATS, however, provides directsupportforfunctionsofmultiplearguments.ThereisevensomelimitedsupportinATSforvariadicfunctions,thatis,functionsofindefinitenumberofarguments(e.g.,thefamous printf functioninC).ThisisatopicIwillcoverelsewhere.

Page 42: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

FunctionInterface

Theinterfaceforafunctionspecifiesthetypeassignedtothefunction.Givenabinaryfunctionfooofthetype(T1,T2)->T3,itsinterfacecanbewrittenasfollows:

funfoo(arg1:T1,arg2:T2):T3

where arg1 and arg2 maybe replacedwithanyother legal identifiers for functionarguments.Forfunctionsofmoreorfewerarguments,interfacescanbewritteninasimilarfashion.Forinstance,wehavethefollowinginterfacesforvariousfunctionsonintegers:

funsucc_int(x:int):int//successor

funpred_int(x:int):int//predecessor

funadd_int_int(x:int,y:int):int//+

funsub_int_int(x:int,y:int):int//-

funmul_int_int(x:int,y:int):int//*

fundiv_int_int(x:int,y:int):int///

funmod_int_int(x:int,y:int):int//modulo

fungcd_int_int(x:int,y:int):int//greatestcommondivisor

funlt_int_int(x:int,y:int):bool//<

funlte_int_int(x:int,y:int):bool//<=

fungt_int_int(x:int,y:int):bool//>

fungte_int_int(x:int,y:int):bool//>=

funeq_int_int(x:int,y:int):bool//=

funneq_int_int(x:int,y:int):bool//<>

funmax_int_int(x:int,y:int):int//maximum

funmin_int_int(x:int,y:int):int//minimum

funprint_int(x:int):void

funtostring_int(x:int):string

Fornow,Imostlyusefunction interfaces for thepurposeofpresentingfunctions. Iwillshowlaterhowafunctiondefinitioncanbeseparatedintotwoparts:afunctioninterfaceandanimplementationthatimplementsthefunctioninterface.Notethatseparationassuchispivotalforconstructing(large)programsinamodularstyle.

Page 43: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

EvaluationofFunctionCalls

Evaluatingafunctioncallisstraightforward.Assumethatwearetoevaluatethefunctioncall abs(0.0-1.0) undersomeenvironmentENV0,wherethefunction abs isdefinedasfollows:

fnabs(x:double):double=ifx>=0.0thenxelse~x

Wefirstevaluatetheargumentofthecallto ~1.0 underENV0;wethenextendENV0toENV1withabindingbetween x and ~1.0 andstarttoevaluatethebodyof abs underENV1;weevaluatethetest x>=0 to ~1.0>=0 andthento false ,whichindicatesthatwetaketheelse-branch ~x tocontinue;weevaluate ~x to ~(~1.0) andthento 1.0 ;sotheevaluationofthefunctioncall abs(0.0-1.0) returns1.0 .

Page 44: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

RecursiveFunctions

Arecursivefunctionisonethatmaymakecallstoitselfinitsbody.InATS,thekeyword fun isusedtoinitiatethedefinitionofarecursivefunction.Clearly,anon-recursivefunctionisjustaspecialkindofrecursivefunction:thekindthatdoesnotmakeanycallstoitselfinitsbody.Ifoneprefers,onecanuse fun (insteadof fn )toinitiatethedefinitionofanon-recursivefunction.

Iconsiderrecursionthemostenablingfeatureaprogramminglanguagecanprovide.Withrecursion,weareenabledtodoproblem-solvingbasedonastrategyofreduction:Inordertosolveaproblemto which a solution is difficult to find immediately, we reduce the problem to problems that aresimilarbutsimpler,andwerepeat thisreductionprocess ifneededuntilsolutionsbecomeapparent.Letusnowseesomeconcreteexamplesofproblem-solvingthatmakeuseofthisreductionstrategy.

Supposethatwewanttosumupalltheintegersrangingfrom1ton,wherenisagiveninteger.Thiscanbereadilydonebyimplementingthefollowingrecursivefunction sum1 :

funsum1(n:int):int=ifn>=1thensum1(n-1)+nelse0

Tofindoutthesumofalltheintegersrangingfrom 1 to n ,wecall sum1(n) .Thereductionstrategyfor sum1(n) isstraightforward:If n isgreaterthan 1 ,thenwecanreadilyfindthevalueof sum1(n)bysolvingasimplerproblem,thatis,findingthevalueof sum1(n-1) .

Wecanalsosolvetheproblembyimplementingthefollowingrecursivefunction sum2 thatsumsupalltheintegersinagivenrange:

funsum2(m:int,n:int):int=ifm<=nthenm+sum2(m+1,n)else0

Thistime,wecall sum2(1,n) inordertofindoutthesumofalltheintegersrangingfrom 1 to n .Thereductionstrategyfor sum2(m,n) isalsostraightforward:If m islessthan n ,thenwecanreadilyfindthevalueof sum2(m,n) bysolvingasimplerproblem,thatis,findingthevalueof sum2(m+1,n) .Thereasonfor sum2(m+1,n) beingsimplerthan sum2(m,n) isthat m+1 iscloserto n than m is.

Givenintegersmandn,thereisanotherstrategyforsummingupalltheintegersfrommton:Ifmdoesnotexceedn,wecanfindthesumofalltheintegersfrommto(m+n)/2-1andthenthesumofallthe integers from (m+n)/2+1 to n and then sum up these two sums and (m+n)/2. The followingrecursivefunction sum3 isimplementedpreciselyaccordingtothisstrategy:

funsum3

Page 45: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

(m:int,n:int):int=

ifm<=nthenlet

valmn2=(m+n)/2insum3(m,mn2-1)+mn2+sum3(mn2+1,n)

endelse0//endof[if]

//endof[sum3]

Itshouldbenotedthatthedivisioninvolvedintheexpression (m+n)/2 is integerdivisionforwhichroundingisdonebytruncation.

Page 46: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

EvaluationofRecursiveFunctionCalls

Evaluatingacalltoarecursivefunctionisnotmuchdifferentfromevaluatingonetoanon-recursivefunction.Let fib bethefollowingdefinedfunctionforcomputingtheFibonaccinumbers:

funfib(n:int):int=

ifn>=2thenfib(n-1)+fib(n-2)elsen

Suppose thatwe are to evaluate fib(2) under some environmentENV0.Given that 2 is already avalue,weextendENV0toENV1withabindingbetween n and 2 andstart toevaluate thebodyoffib underENV1;clearly,thisevaluationleadstotheevaluationof fib(n-1)+fib(n-2) ;itiseasytosee that evaluating fib(n-1) and fib(n-2) under ENV1 leads to 1 and 0 , respectively, and theevaluationof fib(n-1)+fib(n-2) eventuallyreturns 1 (as theresultof 1+0 ); thus theevaluationoffib(2) underENV0yieldstheintegervalue 1 .

Letusnowevaluate fib(3) underENV0;weextendENV0toENV2withabindingbetween n and 3 ,andstarttoevaluatethebodyof fib underENV2;wethenreachtheevaluationof fib(n-1)+fib(n-2)underENV2;evaluating fib(n-1) underENV2leadstotheevaluationof fib(2) underENV2,whicheventuallyreturns 1 ;evaluating fib(n-2) underENV2leadstotheevaluationof fib(1) underENV2,whicheventuallyreturns 1 ;therefore,evaluating fib(3) underENV0returns 2 (astheresultof 1+1 ).

Page 47: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:CoinChangesforFun

LetSbeafinitesetofpositivenumbers.Theproblemwewanttosolveistofindoutthenumberofdistinctwaysforagivenintegerx tobeexpressedas thesumofmultiplesof thepositivenumberschosenfromS.IfweinterpreteachnumberinSasthedenominationofacoin,thentheproblemaskshowmanydistinctwaysthereexistforagivenvaluextobeexpressedasthesumofasetofcoins.Ifweusecc(S,x)forthisnumber,thenwehavethefollowingpropertiesonthefunctioncc:

cc(S,0)=1foranyS.

Ifx<0,thencc(S,x)=0foranyS.

IfSisemptyandx>0,thencc(S,x)=0.

IfScontainsanumberc, thencc(S,x)=cc(S1,x)+cc(S,x-c),whereS1 is the set formedbyremovingcfromS.

Inthefollowingimplementation,wefixStobethesetconsistingof1,5,10and25.

typedefint4=(int,int,int,int)

valtheCoins=(1,5,10,25):int4

funcoin_get

(n:int):int=

ifn=0thentheCoins.0

elseifn=1thentheCoins.1

elseifn=2thentheCoins.2

elseifn=3thentheCoins.3

else~1(*erroneousvalue*)

//endof[coin_get]

funcoin_change

(sum:int):int=let

funaux(sum:int,n:int):int=

ifsum>0then

(ifn>=0thenaux(sum,n-1)+aux(sum-coin_get(n),n)else0)

else(ifsum<0then0else1)

//endof[aux]

in

aux(sum,3)

end//endof[coin_change]

Page 48: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

The auxiliary function aux defined in the body of the function coin_change corresponds to the ccfunctionmentionedabove.Whenappliedto 1000 ,thefunction coin_change returns 142511 .

Notethattheentirecodeinthissectionplussomeadditionalcodefortestingisavailableon-line.

Page 49: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Tail-CallandTail-Recursion

Supposethatafunctionfoomakesacallinitsbodytoafunctionbar,wherefooandbarmaybethesamefunction.Ifthereturnvalueofthecalltobarisalsothereturnvalueoffoo,thenthiscalltobarisatail-call.Iffooandbararethesame,thenthisisa(recursive)selftail-call.Forinstance,therearetworecursivecallsinthebodyofthefunction f91 definedasfollows:

funf91(n:int):int=

ifn>=101thenn-10elsef91(f91(n+11))

wheretheouterrecursivecallisaselftail-callwhiletheinneroneisnot.

If each recursive call in the body of a function is a tail-call, then this function is a tail-recursivefunction.Forinstance,thefollowingfunction sum_iter istail-recursive:

funsum_iter

(n:int,res:int):int=

ifn>0thensum_iter(n-1,n+res)elseres

//endof[sum_iter]

Atail-recursivefunctionisoftenreferredtoasaniterativefunction.

InATS, the singlemost important optimization is probably theone that turns a self tail-call into alocal jump.Thisoptimizationeffectivelyturnseverytail-recursivefunctioninto theequivalentofaloop.AlthoughATSprovidesdirectsyntacticsupportforconstructingfor-loopsandwhile-loops,thepreferred approach to loop construction in ATS is in general through the use of tail-recursivefunctions.Thisisthecaseprimarilyduetothefactthatthesyntaxforwritingtail-recursivefunctionsiscompatiblewith thesyntaxforotherprogrammingfeatures inATSwhile thesyntaxfor loops ismuchlessso.

Page 50: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:TheEight-QueensPuzzle

Theeight-queenspuzzle is theproblemofpositioningona8x8chessboard8queenpieces so thatnoneofthemcancaptureanyotherpiecesusingthestandardchessmovesdefinedforaqueenpiece.IwillpresentasfollowsasolutiontothispuzzleinATS,reviewingsomeoftheprogrammingfeaturesthathavebeencoveredsofar.Inparticular,pleasenotethateveryrecursivefunctionimplementedinthissolutionistail-recursive.

First,letusintroduceanamefortheintegerconstant8asfollows:

#defineN8

Afterthisdeclaration,eachoccurrenceofthename N istobereplacedwith8.Forrepresentingboardconfigurations,wedefineatype int8 asfollows:

typedefint8=

(

int,int,int,int,int,int,int,int

)//endof[int8]

Avalueofthetype int8 isatupleof8integerswherethefirstintegerstatesthecolumnpositionofthe queen piece on the first row (row 0), and the second integer states the column position of thequeenpieceonthesecondrow(row1),andsoon.

Inordertoprintoutaboardconfiguration,wedefinethefollowingfunctions:

funprint_dots(i:int):void=

ifi>0then(print".";print_dots(i-1))else()

//endof[print_dots]

funprint_row(i:int):void=

(

print_dots(i);print"Q";print_dots(N-i-1);print"\n";

)//endof[print_row]

funprint_board(bd:int8):void=

(

print_row(bd.0);print_row(bd.1);print_row(bd.2);print_row(bd.3);

print_row(bd.4);print_row(bd.5);print_row(bd.6);print_row(bd.7);

print_newline()

)//endof[print_board]

Page 51: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Thefunction print_newline printsoutanewlinesymbolandthenflushesthebufferassociatedwiththestandardoutput.Ifthereaderisunclearaboutwhatbufferflushingmeans,pleasefeelfreetoignorethisaspectof print_newline .

Asanexample,if print_board iscalledontheboardconfigurationrepresentedby@(0,1,2,3,4,5,6,7),thenthefollowing8linesareprintedout:

Q.......

.Q......

..Q.....

...Q....

....Q...

.....Q..

......Q.

.......Q

Givenaboardandtherownumberofaqueenpieceontheboard,thefollowingfunction board_getreturnsthecolumnnumberofthepiece:

funboard_get

(bd:int8,i:int):int=

ifi=0thenbd.0

elseifi=1thenbd.1

elseifi=2thenbd.2

elseifi=3thenbd.3

elseifi=4thenbd.4

elseifi=5thenbd.5

elseifi=6thenbd.6

elseifi=7thenbd.7

else~1//endof[if]

//endof[board_get]

Givenaboard,arownumber iandacolumnnumber j, thefollowingfunction board_set returnsanewboardthatarethesameastheoriginalboardexceptforjbeingthecolumnnumberofthequeenpieceonrowi:

funboard_set

(bd:int8,i:int,j:int):int8=let

val(x0,x1,x2,x3,x4,x5,x6,x7)=bd

in

ifi=0thenlet

valx0=jin(x0,x1,x2,x3,x4,x5,x6,x7)

endelseifi=1thenlet

Page 52: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

valx1=jin(x0,x1,x2,x3,x4,x5,x6,x7)

endelseifi=2thenlet

valx2=jin(x0,x1,x2,x3,x4,x5,x6,x7)

endelseifi=3thenlet

valx3=jin(x0,x1,x2,x3,x4,x5,x6,x7)

endelseifi=4thenlet

valx4=jin(x0,x1,x2,x3,x4,x5,x6,x7)

endelseifi=5thenlet

valx5=jin(x0,x1,x2,x3,x4,x5,x6,x7)

endelseifi=6thenlet

valx6=jin(x0,x1,x2,x3,x4,x5,x6,x7)

endelseifi=7thenlet

valx7=jin(x0,x1,x2,x3,x4,x5,x6,x7)

endelsebd//endof[if]

end//endof[board_set]

Clearly, the functions board_get and board_set are defined in a rather unwieldy fashion. This isentirelydue to theuseof tuples for representingboardconfigurations. Ifwecoulduseanarray torepresent a board configuration, then the implementation would be much simpler and cleaner.However,wehavenotyetcoveredarraysatthispoint.

Letusnowimplementtwotestingfunctions safety_test1 and safety_test2 asfollows:

funsafety_test1

(

i0:int,j0:int,i1:int,j1:int

):bool=

(*

**[abs]:theabsolutevaluefunction

*)

j0!=j1andalsoabs(i0-i1)!=abs(j0-j1)

//endof[safety_test1]

funsafety_test2

(

i0:int,j0:int,bd:int8,i:int

):bool=

ifi>=0then

ifsafety_test1(i0,j0,i,board_get(bd,i))

thensafety_test2(i0,j0,bd,i-1)elsefalse

//endof[if]

elsetrue//endof[if]

//endof[safety_test2]

Thefunctionalitiesofthesetwofunctionscanbedescribedassuch:

Page 53: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Thefunction safety_test1 testswhether aqueenpieceon row i0 andcolumn j0 can captureanotheroneonrow i andcolumn j .

Thefunction safety_test2 testswhetheraqueenpieceonrow i0 andcolumn j0 cancaptureanyotherpiecesonagivenboardwitharownumberlessthanorequalto i .

Wearenowreadytoimplementthefollowingfunction search basedonastandarddepth-firstsearch(DFS)algorithm:

funsearch

(

bd:int8,i:int,j:int,nsol:int

):int=(

//

if

j<N

thenlet

valtest=safety_test2(i,j,bd,i-1)

in

iftest

thenlet

valbd1=board_set(bd,i,j)

in

ifi+1=N

thenlet

val()=print!("Solution#",nsol+1,":\n\n")

val()=print_board(bd1)

in

search(bd,i,j+1,nsol+1)

end//endof[then]

else(

search(bd1,i+1,0(*j*),nsol)//positioningnextpiece

)(*endof[else]*)

//endof[if]

end//endof[then]

elsesearch(bd,i,j+1,nsol)

//endof[if]

end//endof[then]

else(

ifi>0

thensearch(bd,i-1,board_get(bd,i-1)+1,nsol)elsensol

//endof[if]

)(*endof[else]*)

//

)(*endof[search]*)

Page 54: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Thereturnvalueof search isthenumberofdistinctsolutionstotheeightqueenspuzzle.Thesymbolprint! inthebodyof search isaspecialidentifierinATS:Ittakesanindefinitenumberofargumentsand then applies print to each of them. Following is the first solution printed out by print_boardduringacalltothefunction search :

Q.......

....Q...

.......Q

.....Q..

..Q.....

......Q.

.Q......

...Q....

Thereare92distinctsolutionsintotal.

Notethattheentirecodeinthissectionplussomeadditionalcodefortestingisavailableon-line.

Page 55: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

MutuallyRecursiveFunctions

Acollectionoffunctionsaredefinedmutuallyrecursivelyifeachfunctioncanmakecallsinitsbodyto any functions in this collection. Mutually recursive functions are commonly encountered inpractice.

Asanexample,letPbeafunctiononnaturalnumbersdefinedasfollows:

P(0)=1

P(n+1)=1+thesumoftheproductsofiandP(i)forirangingfrom1ton

Letus introducea functionQsuch thatQ(n) is the sumof theproductsof i andP(i) for i rangingfrom1ton.ThenthefunctionsPandQcanbedefinedmutuallyrecursivelyasfollows:

P(0)=1

P(n+1)=1+Q(n)

Q(0)=0

Q(n+1)=Q(n)+(n+1)*P(n+1)

ThefollowingimplementationofPandQisadirecttranslationoftheirdefinitionsintoATS:

funP(n:int):int=ifn>0then1+Q(n-1)else1

andQ(n:int):int=ifn>0thenQ(n-1)+n*P(n)else0

Notethatthekeyword and isusedtocombinefunctiondefinitions.

Page 56: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

MutuallyDefinedTail-Recursion

Supposethatfooandbararetwomutuallydefinedrecursivefunctions.Inthebodyoffooorbar,atail-calltofooorbarisamutuallyrecursivetail-call.Forinstance,thefollowingtwofunctions isevnand isodd aremutuallyrecursive:

funisevn(n:int):bool=ifn>0thenisodd(n-1)elsetrue

andisodd(n:int):bool=ifn>0thenisevn(n-1)elsefalse

Themutuallyrecursivecallto isodd inthebodyof isevn isatail-call,andthemutuallyrecursivecallto isevn inthebodyof isodd isalsoatail-call.Ifwewantthatthesetwotail-callsbecompiledintolocaljumps,weshouldreplacethekeyword fun withthekeyword fnx asfollows:

fnxisevn(n:int):bool=ifn>0thenisodd(n-1)elsetrue

andisodd(n:int):bool=ifn>0thenisevn(n-1)elsefalse

WhattheATScompilerdoesinthiscaseistocombinethesetwofunctionsintoasingleonesothateachmutuallyrecursivetail-call in theirbodiescanbeturnedintoaself tail-call in thebodyof thecombinedfunction,whichisthenreadytobecompiledintoalocaljump.

WhenwritingcodecorrespondingtoembeddedloopsinanimperativeprogramminglanguagesuchasCor Java,weoftenneed tomakesure thatmutually recursive tail-calls arecompiled into localjumps.Thefollowingfunction print_multable is implemented toprintouta standardmultiplicationtablefornonzerodigits:

fun

print_multable

((*void*))=let

//

#defineN9

//

fnx

loop1

(i:int):void=

ifi<=Nthenloop2(i,1)else()

//

and

loop2

(i:int,j:int):void=

ifj<=i

thenlet

val()=ifj>=2thenprint""

Page 57: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

val()=$extfcall(void,"printf","%dx%d=%2.2d",j,i,j*i)

in

loop2(i,j+1)

end//endof[then]

elselet

val()=print_newline()inloop1(i+1)

end//endof[else]

//endof[if]

//

in

loop1(1)

end//endof[print_multable]

Thefunctions loop1 and loop2 aredefinedmutuallyrecursively,andthemutuallyrecursivecallsintheirbodiesarealltail-calls.Thekeyword fnx indicatestotheATScompilerthatthefunctions loop1and loop2 should be combined so that these tail-calls can be compiled into local jumps. In a casewhere N isalargenumber(e.g.,1,000,000),calling loop1 mayruntheriskofstackoverflowifthesetail-callsarenotcompiledintolocaljumps.

Whencalled,thefunction print_multable printsoutthefollowingmultiplicationtable:

1x1=01

1x2=022x2=04

1x3=032x3=063x3=09

1x4=042x4=083x4=124x4=16

1x5=052x5=103x5=154x5=205x5=25

1x6=062x6=123x6=184x6=245x6=306x6=36

1x7=072x7=143x7=214x7=285x7=356x7=427x7=49

1x8=082x8=163x8=244x8=325x8=406x8=487x8=568x8=64

1x9=092x9=183x9=274x9=365x9=456x9=547x9=638x9=729x9=81

Insummary,theveryabilitytoturnmutuallyrecursivetail-callsintolocaljumpsmakesitpossibletoimplement embedded loops as mutually tail-recursive functions. This ability is indispensable foradvocatingthepracticeofreplacingloopswithrecursivefunctionsinATS.

Page 58: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

EnvlessFunctionsandClosure-Functions

Iuseenvless as a shorthand for environmentless,which isnot a legalwordbut I suppose thatyouhavenoproblemfiguringoutwhatitmeans.

Anenvlessfunctionisrepresentedbyapointerpointingtosomeplaceinacodesegmentwheretheobject code for executing a call to this function is located. Every function in the programminglanguageCisenvless.Aclosure-function isalsorepresentedbyapointer,but thepointerpoints tosomeplaceinaheapwhereatupleisallocated(atrun-time).Usually,thefirstcomponentofthistupleisapointerrepresentinganenvlessfunctionandtherestofthecomponentsrepresentsomebindings.Atupleassuchisoftenreferredtoasaclosure-functionorsimplyclosure,whichcanbethoughtofasanenvless functionpairedwithanenvironment. It ispossible that theenvironmentofaclosure-functionisempty,butthisdoesnotequateaclosure-functionwithanenvlessfunction.EveryfunctioninfunctionallanguagessuchasMLandHaskellisaclosure-function.

Inthefollowingexample,thefunction sum ,whichisassignedthetype (int)->int ,sumsupalltheintegersbetween1andagivennaturalnumber:

funsum

(n:int):int=let

funloop

(

i:int,res:int

):<cloref1>int=

ifi<=nthenloop(i+1,res+i)elseres

//endof[loop]

in

loop(1(*i*),0(*res*))

end//endof[sum]

Theinnerfunction loop isaclosure-functionasisindicatedbythespecialsyntax :<cloref1> ,andthetypeassignedto loop isdenotedby (int,int)-<cloref1>int .Hence,envlessfunctionsandclosure-functionscanbedistinguishedattheleveloftypes.

If the syntax :<cloref1> is replaced with the colon symbol : alone, the code can still passtypecheckingbut itscompilationmayeventually lead toawarningorevenanerror indicating thatloop cannotbecompiledintoatoplevelfunctioninC.Thereasonforthiswarning/errorisduetothebodyof loop containingavariable n thatisneitherattoplevelnorapartoftheargumentsof loopitself. It is straightforward to make loop an envless function by including n as an argument in

Page 59: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

additiontotheoriginalones:

funsum

(n:int):int=let

funloop

(

n:int,i:int,res:int

):int=

ifi<=nthenloop(n,i+1,res+i)elseres

//endof[loop]

in

loop(n,1(*i*),0(*res*))

end//endof[sum]

Asamatteroffact,whathappensduringcompilationisthatthefirstimplementationof sum and loopgets translated, more or less, into the second implementation, and there is no actual creation ofclosuresatrun-time.

Theneedforcreatingclosuresoftenappearswhenafunctionisnotdirectlyapplied.Forinstance,thereturn value of a function callmay also be a function. In the following code, the defined functionaddx returns another function when applied to a given integer x , and the returned function is aclosure-function,whichalwaysaddstheinteger x toitsownargument:

funaddx(x:int):int-<cloref1>int=lamy=>x+y

valplus1=addx(1)//[plus1]isofthetypeint-<cloref1>int

valplus2=addx(2)//[plus2]isofthetypeint-<cloref1>int

Itshouldbeclearthat plus1(0) and plus2(0) return 1 and 2 ,respectively.Theclosure-functionthatis given thename plus1 consists of an envless function and an environment binding x to 1 . Theenvlessfunctioncanessentiallybedescribedbythepseudosyntax lam(env,y)=>env.x+y ,whereenv and env.x refertoanenvironmentandthevaluetowhich x isboundinthatenvironment.Whenevaluating plus1(0) ,wecanfirstbind env and y to theenvironment in plus1 and theargument 0 ,respectively,andthenstarttoevaluatethebodyoftheenvlessfunctionin plus1 ,whichis env.x+y .Clearly,thisevaluationyieldsthevalue 1 asisexpected.

Closuresareoftenpassedasargumentstofunctionsthatarereferredtoashigher-orderfunctions.Itisalsofairlycommonforclosurestobeembeddedindatastructures.

Page 60: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Higher-OrderFunctions

A higher-order function is a function that take another function as its argument. For instance, thefollowingdefinedfunction rtfind isahigher-orderone:

funrtfind

(f:int->int):int=let

funloop(

f:int->int,n:int

):int=

iff(n)=0thennelseloop(f,n+1)

//endof[loop]

in

loop(f,0)

end//endof[rtfind]

Givenafunctionfromintegerstointegers, rtfind searchesforthefirstnaturalnumberthatisarootof the function.For instance,calling rtfind on thepolynomial function lam x => x * x - x - 110returns 11 .Notethat rtfind loopsforeverifitisappliedtoafunctionthatdoesnothavearoot.

Higher-order functions can greatly facilitate code reuse, and I now present a simple example toillustratethispoint.Thefollowingdefinedfunctions sum and prod computethesumandproductoftheintegersrangingfrom1toagivennaturalnumber,respectively:

funsum(n:int):int=ifn>0thensum(n-1)+nelse0

funprod(n:int):int=ifn>0thenprod(n-1)*nelse1

Thesimilaritybetweenthefunctions sum and prod isevident.Wecandefineahigher-function ifoldandthenimplement sum and prod basedon ifold :

funifold

(n:int,f:(int,int)->int,ini:int):int=

ifn>0thenf(ifold(n-1,f,ini),n)elseini

//endof[ifold]

funsum(n:int):int=ifold(n,lam(res,x)=>res+x,0)

funprod(n:int):int=ifold(n,lam(res,x)=>res*x,1)

Ifweeverwanttocomputethesumofthesquaresoftheintegersrangingfrom1toagivennaturalnumbern,wecanreadilydoitbydefiningafunctionbasedon ifold asfollows:

funsqrsum(n:int):int=ifold(n,lam(res,x)=>res+x*x,0)

Page 61: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Supposewegeneralize sqrsum tothefollowingfunction sqrmodsum inordertocomputethesumofthesquaresoftheintegersrangingfrom1tonthataremultiplesofagivennumberd:

funsqrmodsum(n:int,d:int):int=

ifold(n,lam(res,x)=>ifxmoddthenres+x*xelseres,0)

//endof[sqrmodsum]

For someone unfamilarwith the distinction between an envless function and a closure-function, itmaybeabitsuprisingtolearnthatthisgeneralizationdoesnotactuallywork.Thesimplereasonisthat ifold expectsitssecondargumenttobeanenvlessfunctionbutthefunctionpassedto ifold inthe body of sqrmodsum is clearly not envless (due to its use of d ). To address the issue, we canimplementavariantof ifold asfollowsandthenimplement sqrmodsum basedonthisvariant:

funifold2

(

n:int,f:(int,int)-<cloref1>int,ini:int

):int=

ifn>0thenf(ifold2(n-1,f,ini),n)elseini

//endof[ifold2]

funsqrmodsum(n:int,d:int):int=

ifold2(n,lam(res,x)=>ifxmoddthenres+x*xelseres,0)

//endof[sqrmodsum]

While ifold2 isindeedmoregeneralthan ifold , thisgeneralitydoescomewithaprice.Wheneversqrmodsum is called, a closure-function must be created on heap and then passed to ifold2 ; thisclosure-function isofno furtheruseafter thecall returnsand thememory itoccupiescanonlybeproperlyrelcaimedthroughgarbagecollection(GC).Therefore,callingfunctionslike sqrmodsum canreadily result inmemory leaks in a settingwhereGC is not available. Fortunately, there are alsolinearclosure-functionsinATS,whichdonotcauseanymemoryleaksevenintheabsenceofGCastheyarerequiredtobeexplicitlyfreedbytheprogrammer.Iwillcoverthisinterestingprogrammingfeatureelsewhere.

AsmorefeaturesofATSareintroduced,higher-orderfunctionswillbecomeevenmoreeffectiveinfacilitatingcodereuse.

Page 62: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:BinarySearchforFun

While binary search is often performed on an ordered array to checkwhether a given element isstored in thatarray, itcanalsobeemployed tocompute the inverseofan increasingordecreasingfunction on integers. In the following code, the defined function bsearch_fun returns an integer i0suchthatf(i)<=x0holdsforirangingfromlbtoi0,inclusive,andx0<f(i)holdsforirangingfromi0+1toub,inclusive:

//

//Thetype[uint]isforunsignedintegers

//

funbsearch_fun

(

f:int-<cloref1>uint

,x0:uint,lb:int,ub:int

):int=

iflb<=ubthenlet

valmid=lb+(ub-lb)/2

in

ifx0<f(mid)then

bsearch_fun(f,x0,lb,mid-1)

else

bsearch_fun(f,x0,mid+1,ub)

//endof[if]

endelseub//endof[if]

//endof[bsearch_fun]

Asanexample,thefollowingfunction isqrt isdefinedbasedon bsearch_fun tocomputetheintegersquarerootofagivennaturalnumber,thatis,thelargestintegerwhosesquareislessthanorequaltothegivennaturalnumber:

//

//Assumingthat[uint]isof32bits

//

valISQRT_MAX=(1<<16)-1//=65535

funisqrt

(x:uint):int=

bsearch_fun(lami=>square(g0i2u(i)),x,0,ISQRT_MAX)

//endof[isqrt]

Note that the function g0i2u is for casting a signed integer into an unsigned one and the functionsquare returnsthesquareofitsargument.

Page 63: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Pleasefindon-linetheentirecodeinthissectionplussomeadditionalcodefortesting.

Page 64: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:AHigher-OrderFunPuzzle

Letusfirstintroduceatypedefinitionasfollows:

typedefI(a:t@ype)=a-<cloref1>a

Givena typeT, I(T) is foraclosure-function thatmapsagiven inputvalueof typeT toanoutputvalueofthesametypeT.GivenafunctionfoftypeI(T),wecancomposefwithitselftoformanotherfunction,whichjustappliesftwicetoagivenargument.Thefollowingfunctiontemplate twice doespreciselythedescribedfunctioncomposition:

fn{a:t0p}

twice(f:I(a)):<cloref>I(a)=lam(x)=>f(f(x))

Letusnowtakealookatsomeinterestingcodeinvolving twice thatisalsolikelytobepuzzling:

//

typedefI0=int

typedefI1=I(I0)

typedefI2=I(I1)

typedefI3=I(I2)

//

valZ=0

valS=lam(x:int):int=<cloref>x+1

valans0=twice<I0>(S)(Z)

valans1=twice<I1>(twice<I0>)(S)(Z)

valans2=twice<I2>(twice<I1>)(twice<I0>)(S)(Z)

valans3=twice<I3>(twice<I2>)(twice<I1>)(twice<I0>)(S)(Z)

//

Notethatthetypedefinitions I0 , I1 , I2 ,and I3 areintroducedtomaketheabovecodemoreeasilyaccessible.

Obviously, Z standsfortheinteger0and S forthesuccessorfunctiononintegers.Also, ans0 equals2asitistheresultofapplying S to Z twice.Let S2 bethefunctionthatapplies S twice.Itisclearthatans1 istheresultofapplying S2 to Z twiceandthusequals4.Withabitmoreeffort,oneshouldbeabletofigureoutthatthevalueof ans2 is16.Whatisthevalueof ans3 ?Ingeneral,whatisthenthvalueinthesequenceof ans0 , ans1 , ans2 ,etc.?Ileavethesequestionsasexercisesfortheinterestedreader.

Pleasefindon-linetheentirecodeinthissectionplussomeadditionalcodefortesting.

Page 65: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 66: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

CurryingandUncurrying

Currying,whichisnamedafterthelogicianHaskellCurry,meanstoturnafunctiontakingmultiplearguments simultaneously into a function of the same body (modulo corresponding recursivefunctioncallsbeingchangedaccordingly)thattakestheseargumentssequentially.Uncurryingmeansprecisely theoppositeofcurrying. In the followingcode,bothof thedefined functions acker1 andacker2 implementtheAckermann'sfunction(whichisfamousforbeingrecursivebutnotprimitiverecursive):

funacker1

(m:int,n:int):int=

(

ifm>0then

ifn>0thenacker1(m-1,acker1(m,n-1))elseacker1(m-1,1)

elsen+1//endof[if]

)

funacker2

(m:int)(n:int):int=

(

ifm>0then

ifn>0thenacker2(m-1)(acker2m(n-1))elseacker2(m-1)1

elsen+1//endof[if]

)

Thefunction acker2 isacurriedversionof acker1 whilethefunction acker1 inanuncurriedversionof acker2 .Applying acker2 toanintegervaluegeneratesaclosure-function,whichcausesamemory-leakunlessitcanbereclaimedbygarbagecollection(GC)atrun-time.

InfunctionallanguagessuchasMLandHaskell,afunctionofmultipleargumentsneedstobeeithercurriedortranslatedintoacorrespondingunaryfunctionofasingleargumentthatitselfisatuple.Insuchlanguages,curryingoftenleadstobetterperformanceatrun-timeandthusispreferred.InATS,functionsofmultipleargumentsaresupporteddirectly.Also,givenafunctionofmultiplearguments,a curried version of the function is likely to perform less efficiently at run-time than the functionitself(duetothetreatmentofcurriedfunctionsbytheATScompileratsopt).Therefore,theneedforcurrying in ATS is greatly diminished. Unless convincing reasons can be given, currying is ingeneralnotarecommendedprogrammingstyleinATS.

Pleasefindon-linetheentirecodeinthissectionplussomeadditionalcodefortesting.

Page 67: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 68: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 69: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter4.DatatypesThefeatureofdatatypesinATSinlargelytakenfromML.

Adatatypeislikeataggeduniontype.Foreachdatatype,therearesomeconstructorsassociatedwithit, and these constructors are needed for constructing values of the datatype. As an example, thefollowingsyntaxdeclaresadatatypenamed intopt :

datatypeintopt=

|intopt_noneof()|intopt_someof(int)

//endof[intopt]

There are two constructors associatedwith intopt : intopt_none ,which is nullary, and intopt_some ,whichisunary.Forinstance, intopt_none() and intopt_some(1) are twovaluesof the type intopt . Inorderforaccessingcomponentsinsuchvalues,amechanismoftenreferredtoaspattern-matchingisprovidedinATS.Iwilldemonstratethroughexamplesthatdatatypespluspatternmatchingcanoffernotonlygreatconvenienceinprogrammingbutalsoclarityincode.

Thecodeemployedforillustrationinthischapterplussomeadditionalcodefortestingisavailableon-line.

Page 70: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Patterns

PatternsinATScanbedefinedinductivelyasfollows:

Certainconstantvaluessuchasintegers,booleans,chars,floatingpointnumbers,andstringsarepatterns.

Thevoid-value()isapattern.

Theunderscoresymbol _ representsaspecialwildcardpattern.

Variablesarepatterns.

Atupleofpatterns,eitherboxedorunboxed,isapattern.

Arecordofpatterns,eitherboxedorunboxed,isapattern.

GivenaconstructorC,apatterncanbeformedbyapplyingCtoagivenlistofpatterns.

Givenavariablexandapatternpat,(x as pat)isareference-pattern,where as isakeyword.

Someotherformsofpatternswillbeintroducedelsewhere.

Eachvariablecanoccuratmostonceinagivenpattern,andthisisreferredasthelinearityrestrictiononvariablesinpatterns.Forinstance,(x,x)isnotalegalpatternasthevariablexappearstwiceinit.However,thisrestrictiondoesnotapplytothevariable _ ,whichrepresentsthewildcardpattern.

Page 71: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Pattern-Matching

Patternmatchingmeansmatchingvaluesagainstpatterns.Inthecasewhereavaluematchesapattern,acollectionofbindingsaregeneratedbetweenthevariablesinthepatternandcertaincomponentsinthevalue.Pattern-matchingisperformedaccordingtothefollowingsetofrules:

Avaluethatmatchesaconstantpatternmustbethesameconstant,andthismatchinggeneratesnobindings.

Thevoid-value()onlymatchesthevoid-pattern(),andthismatchinggeneratesnobindings.

Anyvaluecanmatchthewildcardpattern,andthismatchinggeneratesnobindings.

Any value can match a variable pattern, and this matching generates a binding between thevariableandthevalue.

Atuple-valuematchesatuple-patterniftheyareofthesamelengthandeachvaluecomponentinthe former matches the corresponding pattern component in the latter, and this matchinggeneratesacollectionofbindingsthatistheunionofthebindingsgeneratedfrommatchingthevaluecomponentsinthetuple-valueagainstthepatterncomponentsinthetuple-pattern.

A record-value matches a record-pattern if they have the same field names and each valuecomponent in the formermatches the corresponding pattern component in the latter, and thismatching generates a collection of bindings that is the union of the bindings generated frommatchingthevaluecomponentsintherecord-valueagainstthepatterncomponentsintherecord-pattern.

GivenapatternformedbyapplyingaconstructorCtosomepatternarguments,avaluematchesthispatternifthevalueisformedbyapplyingCtosomevalueargumentsmatchingthepatternarguments,andthismatchinggeneratesacollectionofbindingsthatistheunionofthebindingsgeneratedfrommatchingthevalueargumentsagainstthepatternarguments.

Given a referenced pattern (x as pat), a valuematches the pattern if it matches pat, and thismatchinggeneratesacollectionofbindingsthatextendsthebindingsgeneratedfrommatchingthevalueagainstpatwithabindingfromxtothevalue.

Supposewehaveatuple-value(0,1,2,3)andatuple-pattern(0,_,x,y).Thenthevaluematchesthepatternandthismatchingyieldsbindingsfromxandyto2and3,respectively.

Page 72: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

MatchingClausesandCase-Expressions

Givenapatternpatandanexpressionexp,(pat => exp)isamatchingclause.Thepatternpatandtheexpressionexparereferredtoastheguardandthebodyofthematchingclause.

Givenanexpressionexp0andasequenceofmatchingclausesclseq,acase-expressioncanbeformedassuch:( case exp0 of clseq).Toevaluatethecase-expressionunderagivenenvironmentENV0,wefirst evaluate exp0underENV0 to avalue. If this valuedoesnotmatch theguardof any clause inclseq,thentheevaluationofthecase-expressionaborts.Otherwise,wechoosethefirstclauseinclseqsuchthatthevaluematchestheguardoftheclause.LetENV1betheenvironmentthatextendsENV0withthebindingsgeneratedfromthismatching,andweevaluatethebodyofthechosenclauseunderENV1.Thevalueobtainedfromthisevaluationisthevalueofthecase-expressionbeingevaluated.

Page 73: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

EnumerativeDatatypes

The simplest form of datatypes is for enumerating a finite number of constants. For instance, thefollowingconcretesyntaxintroducesadatatypeofthename wday :

datatypewday=

|Mondayof()

|Tuesdayof()

|Wednesdayof()

|Thursdayof()

|Fridayof()

|Saturdayof()

|Sundayof()

//endof[wday]

wherethefirstbarsymbol(|)isoptional.Thereare7nullaryconstructorsintroducedinthedatatypedeclaration: Monday through Sunday ,whichareforconstructingvaluesofthetype wday .Forinstance,Monday() isavalueofthetype wday .GivenanullaryconstructorC,wecanwriteCforC()asavalue.For instance, we can write Monday for Monday() . However, one should not assume that Tuesday issomethinglike Monday+1 .

The following code implements a function that tests whether a given value of the type wday is aweekdayornot:

funisWeekday

(x:wday):bool=casexof

|Monday()=>true//thefirstbar(|)isoptional

|Tuesday()=>true

|Wednesday()=>true

|Thursday()=>true

|Friday()=>true

|Saturday()=>false

|Sunday()=>false

//endof[isWeekday]

GivenaunaryconstructorC,C()isapatternthatcanonlymatchthevalueC().NotethatC()cannotbewrittenasCwhenitisusedasapattern.If Monday() iswrittenas Monday inthebodyofthefunctionisWeekday ,thenanerrormessageistobereportedduringtypechecking,indicatingthatalltheclausesafter the first one are redundant. This is simply due to Monday being treated as a variable pattern,which is matched by any value. A likely more sensible implementation of isWeekday is given asfollows:

Page 74: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

funisWeekday

(x:wday):bool=casexof

|Saturday()=>false|Sunday()=>false|_=>true

//endof[isWeekday]

This implementationworksbecausepattern-matching isdonesequentiallyat run-time: Ifavalueofthetype wday doesnotmatcheitherof Saturday() and Sunday() ,thenitmustmatchoneof Monday() ,Tuesday() , Wednesday() , Thursday() ,and Friday() .

Page 75: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

RecursivelyDefinedDatatypes

A recursively defined datatype (or recursive datatype for short) is one such that its associatedconstructorsmayformvaluesbyapplyingtovaluesofthedatatypeitself.Forinstance,thefollowingdeclareddatatype charlst isrecursive:

datatypecharlst=

|charlst_nilof()|charlst_consof(char,charlst)

//endof[charlst]

Whenapplied to a character andavalueof the type charlst , the constructor charlst_cons forms avalueofthetype charlst .Asanexample,thefollowingvaluerepresentsacharacterlistconsistingof'a','b'and'c':

charlst_cons('a',charlst_cons('b',charlst_cons('c',charlst_nil())))

Wecandefineafunction charlst_length asfollowstocomputethelengthofagivencharacterlist:

funcharlst_length

(cs:charlst):int=casecsof

|charlst_cons(_,cs)=>1+charlst_length(cs)

|charlst_nil()=>0

//endof[charlst_length]

Notethatthisimplementationisrecursivebutnottail-recursive.Byrelyingonthecommutativityandassociativityofintegeraddition,wecangivethefollowingimplementationof charlst_length thatistail-recursive:

funcharlst_length

(cs:charlst):int=let

//

funloop

(cs:charlst,n:int):int=casecsof

|charlst_cons(_,cs)=>loop(cs,n+1)|charlst_nil()=>n

//endof[loop]

//

in

loop(cs,0)

end//endof[charlst_length]

Notethat thenamingconventionIfollowcloselyinthisbook(andelsewhere)mandatesthatonlyatail-recursivefunctionbegivenanameindicativeofitsbeingaloop.Anon-tail-recursivefunctionis

Page 76: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

not called a loop because it cannot be translated directly to a loop in an imperative programminglanguagelikeC.

Page 77: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ExhaustivenessofPattern-Matching

GivenatypeTandasetofpatterns,ifforanygivenvalueofthetypeTthereisalwaysatleastonepattern in thesetsuch that thevaluematches thepattern, thenpattern-matchingvaluesof the typeTagainstthesetofpatternsisexhaustive.Givenacase-expressionoftheform( case exp0 of clseq),where exp0 is assumed to be of some typeT, if pattern-matching values of the typeT against theguardsofthematchingclausesinclseqisexhaustive,thenthecase-expressionissaidtobepattern-matching-exhaustive.

Thefollowingcodeimplementsafunctionthatfindsthelastcharacterinanon-emptycharacterlist:

funcharlst_last

(cs:charlst):char=

(

casecsof

|charlst_cons(c,charlst_nil())=>c

|charlst_cons(_,cs1)=>charlst_last(cs1)

)

//endof[charlst_last]

The body of charlst_last is a case-expression,which is not pattern-matching-exhaustive: If cs isboundtothevalue charlst_nil() ,thatis,theemptycharacterlist,thannoneofthematchingclausesinthe case-expression can be chosen.When the code is typechecked by atsopt, awarningmessage isissued to indicate the case-expression being non-pattern-matching-exhaustive. If the programmerwantsanerrormessageinstead,thekeyword case shouldbereplacedwith case+ .Iftheprogrammerwants tosuppress thewarningmessage, thekeyword case shouldbereplacedwith case- . Imyselfmostlyuse case+ whencodinginATS.

Thefunction charlst_last canalsobeimplementedasfollows:

funcharlst_last

(cs:charlst):char=

(

casecsof

|charlst_cons(c,cs1)=>

(

case+cs1of

|charlst_nil()=>c|charlst_cons_=>charlst_last(cs1)

)//endof[charlst_cons]

)//endof[charlst_last]

Page 78: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

In this implementation, theoutercase-expression isnotpattern-matching-exhaustivewhile the innerone is.Note that thepattern charlst_cons _ is justa shorthand for charlst_cons(_, _) . In general, apatternoftheform C_ ,whereCisaconstructor(associatedwithsomedatatype),canbematchedbyanyvaluethatisconstructedbyapplyingCtosomevalues.Forinstance,thepattern charlst_nil() canalsobewrittenas charlst_nil_ .

Supposewehaveacase-expressioncontainingonlyonematchingclause,thatis,thecase-expressionis of the form [ case exp0 of pat => exp]. Then we can also write this case-expression as a let-expression:( let val pat = exp0 in exp end ).Forinstance,wegiveanotherimplementationofthefunction charlst_last asfollows:

funcharlst_last

(cs:charlst):char=let

valcharlst_cons(c,cs1)=csincase+cs1of

|charlst_nil()=>c|charlst_cons_=>charlst_last(cs1)

end//endof[charlst_last]

Whenthisimplementationistypecheckedbyatsopt,awarningmessageisissuedtoindicatetheval-declaration being non-pattern-matching-exhaustive. If the programmer wants an error messageinstead, the keyword val should be replacedwith val+ . If the programmer wants to suppress thewarningmessage,thekeyword val shouldbereplacedwith val- .

As values formed by the constructors charlst_nil and charlst_cons are assigned the same typecharlst , it is impossible to rely on typechecking to prevent the function charlst_last from beingappliedtoanemptycharacterlist.Thisisaseriouslimitation.Withdependenttypes,whichallowdatatobedescribedmuchmoreprecisely,wecanensureat theleveloftypesthatafunctionfindingthelastelementofalistcanonlybeappliedtoanon-emptylist.

Page 79: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:BinarySearchTree

Abinarysearchtreeisabinarytreesatisfyingthefollowingproperty:foreachnodeinthetree,thekeystoredinthenodeisgreaterthanorequaltoeverykeystoredintheleftchildofthenodeandlessthanor equal to every key stored in the right child of the node. In otherwords, a binary tree is abinary search tree if a pre-order traversal encounters a sequence of keys ordered ascendingly(according to someorderingonkeys). Inpractice,binary search treesarecommonlyemployed torepresentsetsandmaps.

The followingdeclaration introducesadatatype bstree forbinary search trees inwhich the storedkeysarestrings:

datatypebstree=

|Eof()|Bof(bstree,string,bstree)

//endof[bstree]

Itshouldbenotedthatnoteveryvalueofthetype bstree representsavalidbinarysearchtreeasitiscertainlypossibletoconstructavaluerepresentingabinarytreebutnotabinarysearchtree.

Thefollowingfunction[bstree_inord]doesain-ordertraversalofagivenbinarytree:

funbstree_inord

(

t0:bstree,fwork:string-<cloref1>void

):void=

(

case+t0of

|E()=>()

|B(t1,k,t2)=>

{

val()=bstree_inord(t1,fwork)

val()=fwork(k)

val()=bstree_inord(t2,fwork)

}

)(*endof[bstree_inord]*)

If[t0]isabinarysearchtree,thenthesequenceofkeysprocessedby[fwork]areorderedascendingly.

Givenabinarysearchtreeandakey,thefollowingfunction[bstree_search]checkswhetherthekeyisstoredinsidethetree:

funbstree_search

Page 80: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

(t0:bstree,k0:string):bool=

(

case+t0of

|E()=>false

|B(t1,k,t2)=>let

valsgn=compare(k0,k)

in

case+0of

|_whensgn<0=>bstree_search(t1,k0)

|_whensgn>0=>bstree_search(t2,k0)

|_(*k0=k*)=>true

end//endof[B]

)(*endof[bstree_search]*)

Notethat[bstree_search]returnstrueifthegivenkeyisfound.Otherwise,itreturnsfalse.

Givenabinarysearch treeandakey, the following function [bstree_insert] inserts thekey into thetree:

funbstree_insert

(t0:bstree,k0:string):bstree=

(

case+t0of

|E()=>B(E,k0,E)

|B(t1,k,t2)=>let

valsgn=compare(k0,k)

in

case+0of

|_whensgn<0=>B(bstree_insert(t1,k0),k,t2)

|_whensgn>0=>B(t1,k,bstree_insert(t2,k0))

|_(*k0=k*)=>t0//[k0]foundandnoactualinsertion

end//endof[B]

)(*endof[bstree_insert]*)

Notethat[bstree_insert]insertsthekeyonlyifitisnotalreadystoredinsidethegiventree.Also,ifinserted,thekeyisalwaysstoredinanewlycreatedleafnode.

Pleasefindon-linetheentiretyofthecodeinthissectionplussomeadditionalcodefortesting.

Page 81: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:EvaluatingIntegerExpressions

Forrepresentingintegerexpressions,wedeclareadatatype IEXP asfollows:

datatypeIEXP=

|IEXPcstofint//constants

|IEXPnegof(IEXP)//negative

|IEXPaddof(IEXP,IEXP)//addition

|IEXPsubof(IEXP,IEXP)//subtraction

|IEXPmulof(IEXP,IEXP)//multiplication

|IEXPdivof(IEXP,IEXP)//division

//endof[IEXP]

Themeaningoftheconstructorsassociatedwith IEXP shouldbeobvious.Avalueofthetype IEXP isoften referred toasanabstract syntax tree.For instance, theabstract syntax tree for theexpression(~1+(2-3)*4)isthefollowingone:

IEXPadd(IEXPneg(IEXPcst(1)),IEXPmul(IEXPsub(IEXPcst(2),IEXPcst(3)),IEXPcst(4)))

Translatingan integerexpressionwritten in somestring form intoanabstract syntax tree is calledparsing,whichwewillnotdohere.Thefollowingdefinedfunction eval_iexp takestheabstractsyntaxtreeofanintegerexpressionandreturnsanintegerthatisthevalueoftheexpression:

fun

eval_iexp

(e0:IEXP):int=

(

case+e0of

|IEXPcst(n)=>n

|IEXPneg(e)=>~eval_iexp(e)

|IEXPadd(e1,e2)=>eval_iexp(e1)+eval_iexp(e2)

|IEXPsub(e1,e2)=>eval_iexp(e1)-eval_iexp(e2)

|IEXPmul(e1,e2)=>eval_iexp(e1)*eval_iexp(e2)

|IEXPdiv(e1,e2)=>eval_iexp(e1)/eval_iexp(e1)

)(*endof[eval_iexp]*)

Suppose we also allow the construct if-then-else to be use in forming integer expressions. Forinstance,wemaywriteanintegerexpressionlike(if1+2<=3*4then5+6else7-8).Notethatthetest(1+2<=3*4) isabooleanexpressionrather thanan integerexpression.This indicates thatwealsoneed todeclareadatatype BEXP for representingbooleanexpressions.Furthermore, IEXP and BEXPshouldbedefinedmutuallyrecursivelyasfollows:

Page 82: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

datatypeIEXP=

|IEXPcstofint//integerconstants

|IEXPnegof(IEXP)//negative

|IEXPaddof(IEXP,IEXP)//addition

|IEXPsubof(IEXP,IEXP)//subtraction

|IEXPmulof(IEXP,IEXP)//multiplication

|IEXPdivof(IEXP,IEXP)//division

|IEXPifof(BEXP(*test*),IEXP(*then*),IEXP(*else*))

//endof[IEXP]

andBEXP=//[and]forcombiningdatatypedeclarations

|BEXPcstofbool//booleanconstants

|BEXPnegofBEXP//negation

|BEXPconjof(BEXP,BEXP)//conjunction

|BEXPdisjof(BEXP,BEXP)//disjunction

|BEXPeqof(IEXP,IEXP)//equal-to

|BEXPneqof(IEXP,IEXP)//not-equal-to

|BEXPltof(IEXP,IEXP)//less-than

|BEXPlteof(IEXP,IEXP)//less-than-equal-to

|BEXPgtof(IEXP,IEXP)//greater-than

|BEXPgteof(IEXP,IEXP)//greater-than-equal-to

//endof[BEXP]

Evidently,we also need to evaluate boolean expressionswhen evaluating integer expressions. Thefollowing two functions eval_iexp and eval_bexp for evaluating integer and boolean expressions,respectively,aredefinedmutuallyrecursivelyascanbeexpected:

fun

eval_iexp

(e0:IEXP):int=

(

case+e0of

|IEXPcstn=>n

|IEXPneg(e)=>~eval_iexp(e)

|IEXPadd(e1,e2)=>eval_iexp(e1)+eval_iexp(e2)

|IEXPsub(e1,e2)=>eval_iexp(e1)-eval_iexp(e2)

|IEXPmul(e1,e2)=>eval_iexp(e1)*eval_iexp(e2)

|IEXPdiv(e1,e2)=>eval_iexp(e1)/eval_iexp(e1)

|IEXPif

(

e_test,e_then,e_else

)=>

(

eval_iexp(ifeval_bexp(e_test)thene_thenelsee_else)

)//endof[IEXPif]

)(*endof[eval_iexp]*)

Page 83: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

and

eval_bexp

(e0:BEXP):bool=

(

case+e0of

|BEXPcstb=>b

|BEXPneg(e)=>~eval_bexp(e)

|BEXPconj(e1,e2)=>

ifeval_bexp(e1)theneval_bexp(e2)elsefalse

|BEXPdisj(e1,e2)=>

ifeval_bexp(e1)thentrueelseeval_bexp(e2)

|BEXPeq(e1,e2)=>eval_iexp(e1)=eval_iexp(e2)

|BEXPneq(e1,e2)=>eval_iexp(e1)!=eval_iexp(e2)

|BEXPlt(e1,e2)=>eval_iexp(e1)<eval_iexp(e2)

|BEXPlte(e1,e2)=>eval_iexp(e1)<=eval_iexp(e2)

|BEXPgt(e1,e2)=>eval_iexp(e1)>eval_iexp(e2)

|BEXPgte(e1,e2)=>eval_iexp(e1)>=eval_iexp(e2)

)(*endof[eval_bexp]*)

Theintegerandbooleanexpressionsusedinthisexampleareallconstantexpressionscontainingnovariables. Therefore, there is no need for an environment to evaluate them. Iwill present amoreadvancedexampleelsewheretodemonstratehowanevaluatorforasimplecall-by-valuefunctionalprogramminglanguagelikethecoreofATScanbeimplemented.

Pleasefindon-linetheentiretyofthecodeinthissectionplussomeadditionalcodefortesting.

Page 84: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 85: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 86: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter5.ParametricPolymorphismCodesharing isofparamount importance inprogramming. In a typedprogramming language,weoftenencounterasituationwherethesamefunctionalityisneededforvaluesofdifferenttypes.Forinstance,wemayneedtocomputethelengthofalistwhiletheelementsinthelistcanbecharacters,integers,strings,etc.Evidently,wewanttoavoidimplementingalist-lengthfunctionforeachelementtypeas itwouldprobablybe theworst formofcodeduplication.Wewant to implementonesinglefunction that can be applied to any list to compute the length of the list. This list-length functionparameterizes over the element type of a given list, and it behaves uniformly regardlesswhat theelementtypeis.Thisisaformofcodesharingthatisoftenreferredtoasparametricpolymorphism,whichshouldbedistinguishedfromotherformsofpolymorphismsuchasinheritancepolymorphisminobject-orientedprogramming.

Thecodeemployedforillustrationinthischapterplussomeadditionalcodefortestingisavailableon-line.

Page 87: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

FunctionTemplates

A function template is a code template that implements a function. In the following code, twofunctionsaredefinedtoswapvalues:

typedefcharint=(char,int)

typedefintchar=(int,char)

funswap_char_int(xy:charint):intchar=(xy.1,xy.0)

funswap_int_char(xy:intchar):charint=(xy.1,xy.0)

Iftypesareignored,thebodiesof swap_char_int and swap_int_char areidentical.Inordertoavoidthiskind of code duplication, we can first implement a function template swap as follows and thenimplement swap_char_int and swap_int_char basedon swap :

fun{

a,b:t@ype

}swap(xy:(a,b)):(b,a)=(xy.1,xy.0)

funswap_char_int(xy:charint):intchar=swap<char,int>(xy)

funswap_int_char(xy:intchar):charint=swap<int,char>(xy)

Itshouldbenotedthatafunctiontemplateisnotafirst-classvalueinATS:Thereisnoexpressionforrepresenting a function template. The syntax {a,b:t@ype} following the keyword fun representstemplateparametersorarguments.Theunusualsymbol t@ype isasortforstatictermsrepresentingtypesofunspecifiedsize,wherethesizeofatypeis thenumberofbytesneededforrepresentingavalueofthetype(undertheassumptionthatallofthevaluesofthetypehavethesamesize).Thereisanother sort type in ATS, which is for static terms representing types of size equal to one wordexactly,thatis,4bytesona32-bitmachineor8bytesona64-bitmachine.Thesyntax swap<char,int> ,wherenospaceisallowedbetween swap and < ,standsforaninstanceofthefunctiontemplate swapin which the parameters a and b are replaced with char and int , respectively. The syntaxswap<int,char> isinterpretedsimilarly.

Adifferentstyleofimplementationof swap isgivenasfollows:

fun{a:t@ype}{b:t@ype}swap2(xy:(a,b)):(b,a)=(xy.1,xy.0)

wherethetemplateparametersaregivensequentially(insteadofsimultaneously).Thefollowingcodeshowshow swap2 canbeinstantiatedtoforminstances:

funswap_char_int(xy:charint):intchar=swap2<char><int>(xy)

funswap_int_char(xy:intchar):charint=swap2<int><char>(xy)

Page 88: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Notethat >< isaspecialsymbol(ofthenameGTLT)andnospaceisallowedbetween > and < .

Asanotherexample,ahigher-orderfunctiontemplateforcomposing(closure)functionsisgivenasfollows:

typedef

cfun(t1:t@ype,t2:t@ype)=t1-<cloref1>t2

fun{

a,b,c:t@ype

}compose(

f:cfun(a,b),g:cfun(b,c)

):<cloref1>cfun(a,c)=lamx=>g(f(x))

valinc_by_1=lam(x:int):int=<cloref>x+1

valmul_by_2=lam(x:int):int=<cloref>x*2

valf_2x_1=compose<int,int,int>(mul_by_2,inc_by_1)

valf_2x_2=compose<int,int,int>(inc_by_1,mul_by_2)

Itshouldbeclearthatthevalue f_2x_1 representsthefunctionthatmultipliesitsintegerargumentby2and then adds 1 to the result. Similarly, the value f_2x_2 represents the function that adds 1 to itsintegerargumentandthenmultipliestheresultby2.

InATS,functiontemplatesaretypecheckedbutnotcompiledtocodeinC.Instead,theyarecompiledtoanintermediateform.OnlyinstancesoffunctiontemplatesarecompiledtocodeinC.Supposewehaveafunctiontemplate foo takingonetypeparameterandtwoinstancesfoo<T1>andfoo<T2>areused in a program for some typesT1 andT2. In general, one function inC is generated for eachinstanceoffoowhentheprogramiscompiled.However,ifT1andT2havethesamename,thenthetwoinstancesmayshareonefunctioninC.

PleasenotethatImaysimplyusethenamefunctiontorefertoafunctiontemplatefromnowonifnoconfusionisexpected.

Page 89: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

PolymorphicFunctions

Apolymorphicfunctionisrathersimilartoafunctiontemplate.However,theformerisafirst-classvalue in ATSwhile the latter is not. As an example, the following defined function swap_boxed ispolymorphic:

funswap_boxed{a,b:type}(xy:(a,b)):(b,a)=(xy.1,xy.0)

Thetypevariables a and b areoftenreferredasstaticargumentswhile xy isadynamicargument.Forexample,thefollowingcodemakesuseofthepolymorphicfunction swap_boxed :

valAB=(box("A"),box("B"))

valBA1=swap_boxed{boxstr,boxstr}(AB)

valBA2=swap_boxed(AB)//omittingtypeargumentsmaybefine

where the type boxstr is an explicitly boxed version of string that is defined as boxed(string) .Internally,thereisreallynodifferencebetween string and boxed(string) .If swap_boxed iscalledonapair of the type (T1, T2) for some types T1 and T2, both T1 and T2 are required to be boxed.Otherwise,atype-errorisreported.Forexample,calling swap_boxed on (0,1) yieldsatype-errorasthetype int isnotboxed.Onemaybeattemptedtoformaboxedintegerlike box(0) ,butdoingsoleadstoatype-errorasthereisnoassumptionmadeaboutthesizeofanintegervalueofthetype intinATS.

Whencallingapolymorphic function,weoftenomitpassingstaticargumentsexplicitlyandexpectthemtobesynthesizedbythecompiler.However,therearealsooccasions,whicharenotuncommon,wherestaticargumentsneedtobesuppliedexplicitlyaseithertheycannotbesuccessfullysynthesizedorwhatissynthesizedisnotexactlywhatisexpectedbytheprogrammer.

It is also possible to pass static arguments sequentially as is shown in the following style ofimplementationofapolymorphicfunction:

//

funswap2_boxed{a:type}{b:type}(xy:(a,b)):(b,a)=(xy.1,xy.0)

//

valAB=(box("A"),box("B"))

valBA1=swap2_boxed(AB)//bothstaticargumentstobesynthesized

valBA2=swap2_boxed{...}(AB)//bothstaticargumentstobesynthesized

valBA3=swap2_boxed{..}{boxstr}(AB)//1ststaticargumenttobesynthesized

valBA4=swap2_boxed{boxstr}{..}(AB)//2ndstaticargumenttobesynthesized

valBA5=swap2_boxed{..}{..}(AB)//bothstaticargumentstobesynthesized

Page 90: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

valBA6=swap2_boxed{boxstr}{boxstr}(AB)//bothstaticargumentsareprovided

//

Thespecialsyntax {..} indicatestothetypecheckerthatthestaticargument(orarguments)involvedinthecurrentapplicationshouldbesynthesizedwhilethespecialsyntax {...} meansthattherestofstaticargumentsshouldallbesynthesized.

I have seen two kinds of errors involving polymorphic functions that are extremely common inpractice.

Thefirstkindisdepictedinthefollowingexample:

funswap_boxed{a,b:t@ype}(xy:(a,b)):(b,a)=(xy.1,xy.0)

Noticethatthesortfortypevariables a and b is t@ype (insteadof type ).Whilethisexamplecanpasstypechecking,itscompilationresultsinacompile-timeerrorthatmayseemmysterioustomanyprogrammers.Thesimplereasonforthiserroristhatthecompilercannotfigureoutthesizeof a and b whentryingtogeneratecodeinCasthesort t@ype isfortypesofunspecifiedsize.

Thesecondkindisdepictedinthefollowingexample:

fun{a,b:type}swap_boxed(xy:(a,b)):(b,a)=(xy.1,xy.0)

Strictlyspeaking,thereisreallynoerrorinthiscase.Ifdefinedassuch, swap_boxed isafunctiontemplate instead of a polymorphic function. However, such a function template is severelyrestrictedasitcannotbeinstantiatedwithtypesthatarenotboxed.Whilethiscouldbeintended,itisveryunlikely.

Giventhepotentialconfusion,whydoweneedbothfunctiontemplatesandpolymorphicfunctions?Atthisstage,itiscertainlyplausiblethatweprogramonlywithfunctiontemplatesandmakenouseof polymorphic functions. However, polymorphic functions simply become indispensible in thepresence dependent types. There will actually be numerous occasions where we encounterpolymorphicfunctiontemplates,thatis,templatesforpolymorphicfunctions.

Page 91: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

PolymorphicDatatypes

Code sharing also applies to datatype declarations. For instance, a commonly used polymorphicdatatype list0 isdeclaredasfollows:

datatype

list0(a:t@ype)=

|list0_nil(a)of()|list0_cons(a)of(a,list0a)

//endof[list0]

Moreprecisely, list0 is a type constructor.Given a typeT,we can forma type list0(T) for listsconsistingofelementsof the typeT.For instance, list0(char) is forcharacter lists, list0(int) forinteger lists, list0(list0(int)) for listswhoseelementsare themselves integer lists,etc.To a greatextent,theneedforfunctiontemplatesorpolymorphicfunctionslargelystemsfromtheavailabilityofpolymorphicdatatypes.Asanexample,afunctiontemplate list0_length isimplementedasfollowsforcomputingthelengthofanygivenlist:

fun{a:t@ype}

list0_length(xs:list0a):int=

(

case+xsof

|list0_cons(_,xs)=>1+list0_length<a>(xs)|list0_nil()=>0

)(*endof[list0_length]*)

When applying list0_length to a list xs, we can in general write list0_length(xs) , expecting thetypechecker to synthesize a proper type parameter for list0_length . We may also writelist0_length< T >(xs) if the elements of xs are of the type T. The latter style, though a bit moreverbose,islikelytoyieldmoreinformativemessagesincasetype-errorsoccur.

Anothercommonlyusedpolymorphicdatatype option0 isdeclaredasfollows:

datatype

option0(a:t@ype)=

|option0_none(a)of()|option0_some(a)ofa

//endof[option0]

Atypicaluseof option0 istoperformsomekindoferror-handling.Supposethatwearetoimplementafunctiondoingintegerdivisionandwewanttomakesurethatthefunctionreturnsevenifitiscalledinacasewherethedivisorequals0.Thiscanbedoneasfollows:

Page 92: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

fundivopt

(

x:int,y:int

):option0(int)=

ify!=0thenoption0_some{int}(x/y)elseoption0_none((*void*))

//endof[divopt]

Byinspectingwhat divopt returns,wecantellwhetherintegerdivisionhasbeendonenormallyoranerror of divsion-by-zero has occurred. A realistic use of option0 is shown in the followingimplementationof list0_last :

fun{

a:t@ype

}list0_last

(

xs:list0a

):option0(a)=let

//

funloop

(x:a,xs:list0a):a=

(

case+xsof

|list0_nil()=>x|list0_cons(x,xs)=>loop(x,xs)

)(*endof[loop]*)

//

in

case+xsof

|list0_nil()=>option0_none((*void*))

|list0_cons(x,xs)=>option0_some{a}(loop(x,xs))

end//endof[list0_last]

When applied to a list, list0_last returns an optional value. If the value matches the patternoption0_none() ,thenthelistisempty.Otherwise,thevalueisformedbyapplying option0_some tothelastelementofthegivenlist.

Page 93: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:FunctionTemplatesonLists

In functional programming, lists are ubiquitous.We implement as follows some commonly usedfunctiontemplatesonlists.ItshouldbenotedthatthesetemplatesareallavailableinsomelibraryofATS, where they may be implemented in a significantly more efficient manner due to the use ofcertainprogrammingfeatures(suchaslineardatatypes)thathavenotbeencoveredsofar.

Pleasefindtheentirecodeinthissectionplussomeadditionalcodefortestingon-line.

Appending: list0_append

Giventwolistsxsandysofthetype list0(T) forsometypeT, list0_append(xs,ys) returnsalistthatistheconcatenationofxsandys:

fun{

a:t@ype

}list0_append

(

xs:list0a

,ys:list0a

):list0a=

(

case+xsof

|list0_cons(x,xs)=>

list0_cons{a}(x,list0_append<a>(xs,ys))

|list0_nil((*void*))=>ys

)(*endof[list0_append]*)

Clearly,thisimplementationof list0_append isnottail-recursive.

Reverse-Appending: list0_reverse_append

Giventwolistsxsandysofthetype list0(T) forsometypeT, list0_reverse_append(xs,ys) returnsalistthatistheconcatenationofthereverseofxsandys:

fun{

a:t@ype

}list0_reverse_append

(

xs:list0a,ys:list0a

Page 94: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

):list0a=

(

case+xsof

|list0_cons(x,xs)=>

list0_reverse_append<a>(xs,list0_cons{a}(x,ys))

|list0_nil()=>ys

)(*endof[list0_reverse_append]*)

Clearly,thisimplementationof list0_reverse_append istail-recursive.

Reversing: list0_reverse

Givenalistxs, list0_reverse(xs) returnsthereverseofxs:

fun{a:t@ype}

list0_reverse

(xs:list0a):list0a=list0_reverse_append<a>(xs,list0_nil)

//endof[list0_reverse]

Mapping: list0_map

Given a list xs of the type list0(T1) for some type T1 and a closure function f of the type T1 -<cloref1>T2forsometypeT2, list0_map(xs,f) returnsalistysofthetype list0(T2) :

fun

{a:t@ype}

{b:t@ype}

list0_map

(

xs:list0a,f:a-<cloref1>b

):list0b=

(

case+xsof

|list0_cons(x,xs)=>

list0_cons{b}(fx,list0_map<a><b>(xs,f))

|list0_nil((*void*))=>list0_nil()

)(*endof[list0_map]*)

Thelengthofysequalsthatofxsandeachelementyinysequalsf(x),wherexisthecorrespondingelementinxs.Clearly,thisimplementationof list0_map isnottail-recursive.

Page 95: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Left-Folding: list0_foldleft

Givenxs,iniandf, list0_foldleft(ini,xs,f) computesthevalueoftheexpressionf(...f(f(ini,xs[0]),xs[1]) ...,xs[n-1]),wherenis thelengthofxsandxs[i]referstoelementi inxsforeachi<n.Thefollowingimplementationof list0_foldleft istail-recursive:

fun

{a:t@ype}

{b:t@ype}

list0_foldleft

(

ini:a,xs:list0(b),f:(a,b)->a

):a=

(

case+xsof

|list0_cons

(x,xs)=>list0_foldleft<a><b>(f(ini,x),xs,f)

|list0_nil((*void*))=>ini

)

Right-Folding: list0_foldright

Givenxs,resandf, list0_foldright(xs,res,f) computesthevalueoftheexpressionf(xs[0],f(xs[1],f(...f(xs[n-1],res)...))),wherenisthelengthofxsandxs[i]referstoelementiinxsforeachi<n.Thefollowingimplementationof list0_foldright isnottail-recursive:

fun

{a:t@ype}

{b:t@ype}

list0_foldright

(

xs:list0(a),res:b,f:(a,b)->b

):b=

(

case+xsof

|list0_cons

(x,xs)=>f(x,list0_foldright<a><b>(xs,res,f))

|list0_nil((*void*))=>res

)

Zipping: list0_zip

Page 96: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Giventwolistsxsandysofthetypes list0(T1) and list0(T2) forsometypesT1andT2,respectively,list0_zip(xs,ys) returnsalistzsofthetype list0(@(T1,T2)) :

fun{

a,b:t@ype

}list0_zip

(

xs:list0a

,ys:list0b

):list0@(a,b)=let

typedefab=@(a,b)

in

//

case+(xs,ys)of

|(list0_cons(x,xs),

list0_cons(y,ys))=>

(

list0_cons{ab}((x,y),list0_zip<a,b>(xs,ys))

)

|(_,_)=>list0_nil()

//

end//endof[list0_zip]

Thelengthofzsistheminimumofthelengthsofxsandysandeachelementzinzsequals@(x,y),wherexandyarethecorrespondingelementsinxsandys,respectively.Clearly,thisimplementationof list0_zip isnottail-recursive.

Zippingwith: list0_zipwith

Giventwolistsxsandysofthetypes list0(T1) and list0(T2) forsometypesT1andT2,respectively,andaclosurefunctionfofthetype(T1,T2)-<cloref1>T3forsometypeT3, list0_zipwith(xs, ys,f) returnsalistzsofthetype list0(T3) :

fun

{a,b:t@ype}

{c:t@ype}

list0_zipwith

(

xs:list0a

,ys:list0b

,f:(a,b)-<cloref1>c

):list0c=

Page 97: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

(

case+(xs,ys)of

|(list0_cons(x,xs),

list0_cons(y,ys))=>

(

list0_cons{c}(f(x,y),list0_zipwith<a,b><c>(xs,ys,f))

)

|(_,_)=>list0_nil()

)(*endof[list0_zipwith]*)

Thelengthofzsistheminimumofthelengthsofxsandysandeachelementzinzsisf(x,y),wherex and y are the corresponding elements in xs and ys, respectively.Clearly, this implementation oflist0_zipwith isnottail-recursive.Notethat list0_zipwith behavesexactlylike list0_zip if itsthirdargument f isreplacedwith lam(x,y)=>@(x,y) .Thisfunctiontemplateisalsonamed list0_map2fortheobviousreason.

Page 98: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:MergesortonLists

Mergesortisasimplesortingalgorithmthatisguaranteedtobelog-linear.Itisstableinthesensethatthe order of two equal elements always stay the same after sorting. I give as follows a typicalfunctionalstyleofimplementationofmergesortonlists.

First,letusintroduceabbreviationsforthelistconstructors list0_nil and list0_cons :

#define::list0_cons//writing[::]forlist0_cons

#definecons0list0_cons//writing[cons0]forlist0_cons

#definenil0list0_nil//writing[nil0]forlist0_nil

Notethattheoperator :: isalreadygiventheinfixstatus.Forinstance,thelistconsistingofthefirst5naturalnumberscanbeconstructedasfollows:

cons0(0,cons0(1,2::3::4::nil0()))

Inpractice,thereisofcoursenopointinmixing cons0 with :: .

Wenextimplementafunctiontemplate merge tomergetwogivenorderedlistsintoasingleorderedone:

typedef

lte(a:t@ype)=(a,a)->bool

fun{

a:t@ype

}merge(

xs:list0a,ys:list0a,lte:ltea

):list0a=

(

case+xsof

|cons0(x,xs1)=>(

case+ysof

|cons0(y,ys1)=>

ifx\lteythen

cons0{a}(x,merge<a>(xs1,ys,lte))

else

cons0{a}(y,merge<a>(xs,ys1,lte))

//endof[if]

|nil0()=>xs

)//endof[cons0]

|nil0()=>ys

Page 99: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

)(*endof[merge]*)

Forinstance,supposethat thetwogivenlistsare(1,3,4,8)and(2,5,6,7,9),andthecomparisonfunction(thethirdargumentof merge )isthestandardless-than-or-equal-tofunctiononintegers.Thenthe list returned by merge is (1, 2, 3, 4, 5, 6, 7, 8, 9). The syntax \lte means that the particularoccurrence of lte following the backslash symbol ( \ ) is given the infix status, and thus theexpression x\ltey meansthesameas lte(x,y) .

Thefollowingfunctiontemplate mergesort implementsthestandardmergesortalgorithm:

fun{

a:t@ype

}mergesort

(

xs:list0a,lte:ltea

):list0a=let

//

valn=list0_length<a>(xs)

//

funmsort

(

xs:list0a,n:int,lte:ltea

):list0a=

ifn>=2thensplit(xs,n,lte,n/2,nil0)elsexs

//

andsplit

(

xs:list0a,n:int,lte:ltea,i:int,xsf:list0a

):list0a=

ifi>0thenlet

val-cons0(x,xs)=xs

in

split(xs,n,lte,i-1,cons0{a}(x,xsf))

endelselet

valxsf=list0_reverse<a>(xsf)//makesortingstable!

valxsf=msort(xsf,n/2,lte)andxs=msort(xs,n-n/2,lte)

in

merge<a>(xsf,xs,lte)

end//endof[if]

//

in

msort(xs,n,lte)

end//endof[mergesort]

Page 100: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Supposewewanttosortthelist(8,3,4,1,2,7,6,5,9);wefirstdivideitintotwolists:(8,3,4,1)and(2,7,6,5,9);byperformingmergesortoneachofthem,weobtaintwoorderedlists:(1,3,4,8)and(2,5,6,7,9);bymergingthesetwoorderedlist,weobtaintheorderedlist(1,2,3,4,5,6,7,8,9),whichisapermutationoftheoriginallygivenlist(8,3,4,1,2,7,6,5,9).

Notethatthefunctiontemplate merge isnottail-recursiveasthecallto merge initsbodyisnotatail-call.Thiscanbeaseriousprobleminpractice:Itisalmostcertainthatastackoverflowistooccuriftheaboveimplementationofmergesort isemployedtosorta list that isvery long(e.g.,containing1,000,000elementsormore).Iwilllatergiveatail-recursiveimplementationofthe merge functioninATSthatmakesuseoflineartypes.

Pleasefindtheentirecodeinthissectionplussomeadditionalcodefortestingon-line.

Page 101: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

II.SupportforPracticalProgrammingTableofContents6.EffectfulProgrammingFeatures7.Modularity8.InteractionwithC

Page 102: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 103: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 104: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter6.EffectfulProgrammingFeaturesEffectfulprogrammingfeaturesarethosethatcangenerateeffectsatrun-time.Butwhatisreallyaneffect?Theanswertothisquestionisrathercomplexasitdependsonthemodelofevaluation.Iwillgradually introduce various kinds of effects in this book. In sequential programming, that is,constructing programs to be evaluated sequentially (in contrast to concurrently), an expression iseffectlessifthereexistsavaluesuchthattheexpressionandthevaluecannotbedistinguishedasfarasevaluation isconcerned.For instance, theexpression 1+2 is effectlessas it cannotbedistinguishedfrom thevalue 3 .An effectless expression is also said to bepure.On the other hand, an effectfulexpression is one that can be distinguished from any given values. For instance, the expressionprint("Hello") is effectful as its evaluation results in an observable behavior that distinguishes theexpressionfromanyvalues.Inthiscase, print("Hello") issaidtocertainI/Oeffect.Iftheevaluationofanexpressionnever terminates, then theexpression isalsoeffectul.For instance, letusdefineafunction loop asfollows:

funloop():void=loop()

Thentheexpression loop() canbedistinguishedfromanyvaluesinthefollowingcontext:

letval_=[]inprint("Terminated")end

Ifthehole [] inthecontextisreplacedwith loop() , thentheevaluationoftheresultingexpressioncontinuesforever. If thehole [] is replacedwith anyvalue, then the evaluation leads to the string"Terminated"beingprintedout.Theexpression loop issaidtocontainnon-terminationeffect.

Iwill cover programming features related to exceptional control-flow, persistentmemory storageandsimpleI/Ointhischapter,whichareallofcommonuseinpracticalprogramming.

Thecodeemployedforillustrationinthischapterplussomeadditionalcodefortestingisavailableon-line.

Page 105: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Exceptions

Theexceptionmechanismprovidesanefficientmeansforreportingaspecialconditionencounteredduringprogramevaluation.Oftensuchaspecialconditionindicatesanerror,butitisnotuncommontoemployexceptionstoaddressissuesthatarenotrelatedtoerrors.

The type exn ispredefined inATS.Onemay thinkof exn asanextensibledatatype forwhichnewconstructors can always be declared. For instance, two exception constructors are declared asfollows:

exceptionFatalError0of()

exceptionFatalError1of(string)

Theconstructor FatalError0 isnullarywhiletheconstructor FatalError1 isunary.Exceptionvalues,thatis,valuesofthetype exn canbeformedbyapplyingexceptionconstructorstoproperarguments.Forinstance, FatalError0() and FatalError1("division-by-zero") are twoexceptionvalues (orsimplyexceptions).Inthefollowingprogram,afunctionforintegerdivisionisimplemented:

exceptionDivisionByZeroof()

fundivexn(x:int,y:int):int=

ify!=0thenthenx/yelse$raiseDivisionByZero()

//endof[divexn]

When the function call divexn(1, 0) is evaluated, the exception DivisionByZero() is raised. Thekeyword $raise inATSissolelyforraisingexceptions.

Araise-expressionisoftheform( $raise exp)forsomeexpressionexp.Clearly,iftheevaluationofexp returns avalue, then the evaluationof ( $raise exp) leads to a raisedexception.Therefore, theevaluationofaraise-expressioncanneverreturnavalue,andthisjustifiesthataraise-expressioncanbegivenanytype.

A raised exception can be captured. If it is not captured, the raised exception aborts the programevaluationthatissueditinthefirstplace.InATS,atry-expression(ortry-with-expression)isoftheform( try exp with clseq),where try isakeyword,expisanexpression, with isalsoakeyword,andclseqisasequenceofmatchingclauses.Whenevaluatingsuchatry-expression,wefirstevaluateexp.Iftheevaluationofexpleadstoavalue,thenthevalueisalsothevalueofthetry-expression.Iftheevaluationofexpleadstoaraisedexception,thenwematchtheexceptionagainsttheguardsofthematching clauses in clseq. If there is a match, the raised exception is caught and we continue to

Page 106: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

evaluatethebodyofthefirstclausewhoseguardismatched.Ifthereisnomatch,theraisedexceptionisuncaught.Inatry-expression,thewith-partisoftenreferredtoasanexception-handler.

Let us now see an example that involves raising and capturing an exception. In the followingprogram,threefunctionsaredefinedtocomputetheproductoftheintegersinagivenlist:

funlistprod1

(

xs:list0(int)

):int=

(

case+xsof

|list0_nil()=>1

|list0_cons(x,xs)=>x*listprod1(xs)

)(*endof[listprod1]*)

funlistprod2

(

xs:list0(int)

):int=

(

case+xsof

|list0_nil()=>1

|list0_cons(x,xs)=>

ifx=0then0elsex*listprod2(xs)

//endof[list0_cons]

)(*endof[listprod2]*)

funlistprod3

(

xs:list0(int)

):int=let

exceptionZEROof()

funaux(xs:list0(int)):int=

case+xsof

|list0_cons(x,xs)=>

ifx=0then$raiseZERO()elsex*aux(xs)

|list0_nil()=>1

//endof[aux]

in

tryaux(xs)with~ZERO()=>0

end//endof[listprod3]

Whilethesefunctionscanallbedefinedtail-recursively,theyarenotsoastomakeapointthatshouldbeclearshortly.Undoubtedly,weallknowthefollowingsimplefact:

Page 107: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Iftheinteger0occursinagivenlist,thentheproductoftheintegersinthelistis0regardlesswhatotherintegersare.

Thefunction listprod1 isdefinedinastandardmanner,anditdoesnotmakeanyuseofthestatedfact.Thefunction listprod2 isdefinedinamannerthatmakesonlypartialuseofthestatedfact.Toseethereason,letusevaluateacallto listprod2 on [1,2,3,0,4,5,6] ,whichdenotesalistconsistingofthe 7mentioned integers.The evaluation of this call eventually leads to the evaluation of 1*(2*(3*(listprod([0,4,5,6])))) ,which then leads to 1*(2*(3*0)) , and then to 1*(2*0) , and then to 1*0 , andfinally to 0 .However,whatwe reallywant is for the evaluation to return 0 immediately once theinteger 0 is encountered in the list, and this is accomplished by the function listprod3 . Whenevaluatingacall to listprod3 on [1, 2, 3, 0, 4, 5, 6] ,we eventually reach the evaluation of thefollowingexpression:

try1*(2*(3*(aux([0,4,5,6]))))with~ZERO()=>0

Evaluating aux([0,4,5,6]) leads to the exception ZERO() being raised, and this raised exception iscaught and 0 is returned as the value of the call to listprod3 . Note that the pattern guard of thematchingclausefollowingthekeyword with is ~ZERO() .Iwillexplaintheneedforthetildesymbol ~elsewhere.Fornow, it suffices tosay that exn is a linear typeandeachexceptionvalue is a linearvalue,whichmustbeconsumedorre-raised.Thetildesymbol ~ indicatesthatthevaluematchingthepatternfollowing ~ isconsumed(andthememoryforholdingthevalueisfreed).

Exceptionsarenotaprogrammingfeaturethatiseasytomaster,andmisusingexceptionsisabundantinpractice.Sopleasebepatientwhenlearningthefeatureandbecautiouswhenusingit.

Page 108: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:TestingforBraunTrees

Brauntreesarespecialbinarytreesthatcanbedefinedinductivelyasfollows:

Ifabinarytreeisempty,thenitisaBrauntree.

IfbothchildrenofabinarytreeareBrauntreesandthesizeoftheleftchildminusthesizeoftherightchildequals0or1,thenthebinarytreeisaBrauntree.

Givenanaturalnumbern,thereisexactlyoneBrauntreeofsizen.ItisstraightforwardtoprovethatBrauntreesarebalanced.

Apolymorphicdatatypeisdeclaredasfollowsforrepresentingbinarytrees:

datatypetree(a:t@ype)=

|tree_nilof((*void*))

|tree_consof(a,tree(a)(*left*),tree(a)(*right*))

//endof[tree]//endof[datatype]

Thefollowingdefinedfunction brauntest0 testswhetheragivenbinarytreeisaBrauntree:

fun{

a:t@ype

}size(t:treea):int=case+tof

|tree_nil()=>0

|tree_cons(_,tl,tr)=>1+size(tl)+size(tr)

//endof[size]

fun{

a:t@ype

}brauntest0

(t:treea):bool=

(

case+tof

|tree_nil()=>true

|tree_cons(_,tl,tr)=>let

valcond1=brauntest0(tl)andalsobrauntest0(tr)

in

ifcond1thenlet

valdf=size(tl)-size(tr)in(df=0)orelse(df=1)

endelsefalse

end//endof[tree_cons]

)(*endof[brauntest0]*)

Page 109: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Theimplementationof brauntest0 followsthedefinitionofBrauntreesclosely.Ifappliedtobinarytrees of size n, the time-complexity of the function size is O(n) and the time-complexity of thefunction brauntest0 isO(n(log(n))).

Inthefollowingprogram,thedefinedfunction brauntest1 alsotestswhetheragivenbinarytreeisaBrauntree:

fun{

a:t@ype

}brauntest1

(t:treea):bool=let

exceptionNegativeof()

funaux(t:treea):int=

(

case+tof

|tree_nil()=>0

|tree_cons(_,tl,tr)=>let

valszl=aux(tl)andszr=aux(tr)

valdf=szl-szr

in

ifdf=0orelsedf=1then1+szl+szrelse$raiseNegative()

end//endof[tree_cons]

)(*endof[aux]*)

in

trylet

val_=aux(t)

in

true//[t]isaBrauntree

endwith

~Negative()=>false//[t]isnotaBrauntree

//endof[try]

end//endof[brauntest1]

Clearly,abinarytreecannotbeaBrauntreeifoneofitssubtrees,properorimproper,isnotaBrauntree.Theauxiliaryfunction aux isdefinedtoreturnthesizeofabinarytreeifthetreeisaBrauntreeorraiseanexceptionotherwise.Whentheevaluationofthetry-expressioninthebodyof brauntest1starts,thecallto aux onabinarytreetisfirstevaluated.Iftheevaluationofthiscallreturns,thentisaBrauntreeandthebooleanvalue true isreturnedasthevalueofthetry-expression.Otherwise,theexception Negative() israisedandthencaught,andthebooleanvalue false isreturnedasthevalueofthetry-expression.Thetimecomplexityof brauntest1 isthesameasthatof aux ,whichisO(n).

Theuseoftheexceptionmechanismintheimplementationof brauntest1 isaconvincingonebecause

Page 110: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

therangebetweenthepointwhereanexceptionisraisedandthepointwheretheraisedexceptioniscapturedcanspanmanyfunctioncalls.Ifthisrangeisshort(e.g.,spanningonlyonefunctioncall)inacase, thentheprogrammershouldprobablyinvestigatewhether it isasensibleuseof theexceptionmechanism.Forinstance,theuseofexceptioninthefollowingexamplemayseeminterestingbutitactuallyleadstoveryinefficientcode:

fun{

a:t@ype

}list0_length

(xs:list0(a)):int=

try1+list0_length(xs.tail())with~ListSubscriptExn()=>0

//endof[list0_length]

Therefore,makinguseofexceptionsinthisstyleshouldbeavoided.

Pleasefindtheentiretyofthecodeinthissectionplussomeadditionalcodefortestingon-line.

Page 111: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

References

A reference is just a singleton array, that is, an array containing one element. Given a type T, areferenceforstoringavalueof thetypeTisgiventhetyperef(T).Thefollowingsimpleprogrammakesuseofalltheessentialfunctionalitiesonreferences:

valintr=ref<int>(0)//createarefandinit.itwith0

val()=!intr:=!intr+1//increasetheintegerat[intr]by1

The first line creates a reference for storing an integer and initializes itwith the value 0 and thennamesit intr .Notethatthisstyleofreferencecreationcannotbeseparatedfromitsinitialization.Thesecondlineupdatesthereference intr withitscurrentvalueplus1.Ingeneral,givenareferenceroftyperef(T)forsomeT,theexpression!rmeanstofetchthevaluestoredatr,whichisofthetypeT.However,!rcanalsobeusedasaleft-value.Forinstance,theassignment(!r:=exp)meanstoevaluateexp into a value and then store the value into r. Therefore, the value stored in intr is 1 after thesecondlineintheaboveprogramisevaluated.

Variousfunctionsandfunctiontemplatesonreferencesaredeclaredinthefilereference.sats,whichis automatically loaded by atsopt. In particular, it is also possible to read from and write to areference by using the function templates ref_get_elt and ref_set_elt of the following interfaces,respectively:

fun{a:t@ype}ref_get_elt(r:refa):a//!r

fun{a:t@ype}ref_set_elt(r:refa,x:a):void//!r:=x

Referencesareoftenmisused inpractice,especially,bybeginnersof functionalprogrammingwhohad some previous exposure to imperative programming languages such C and Java. Suchprogrammers often think that they can just "translate" their programs inC or Java into functionalprograms.Forexample,thefollowingdefinedfunction sumup issuchanexample,whichsumsupalltheintegersbetween1andagiveninteger,inclusive:

funsumup

(n:int):int=let

vali=ref<int>(1)

valres=ref<int>(0)

funloop():void=

if!i<=nthen(!res:=!res+!i;!i:=!i+1;loop())

//endof[loop]

in

loop();!res

Page 112: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

end//endof[sumup]

Thisisacorrectbutpoorimplementation,anditsstyle,thoughnottheworstofitskind,isdeplorable.Asreferencesareallocatedinheap,readingfromorwritingtoareferencecanbemuchmoretime-consumingthanreadingfromorwritingtoaregister.So,thisimplementationof sumup isunlikelytobe time-efficient.Everycall to sumup creates two references inheapand leaves them therewhen itreturns, and the memory allocated for such references can only be reclaimed through garbagecollection (GC). So, this implementation of sumup is not memory-efficient. More importantly, aprogrammakingheavyuseofreferencesisoftendifficulttoreasonabout.

I consider references a dangerous feature in functional programming. If you want to run yourprogramwithoutGC,pleasedonotcreatereferencesinthebodyofafunction(besidesmanyotherrestrictions). Ifyou find thatyouare inneedof references to "translate" imperativeprograms intofunctionalones,thenitismostlikelythatyouarelostandyouhavenotlearnedwelltoprograminafunctionalstyleyet.

Page 113: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:ACounterImplementation

Let us see as follows the implementation of a counter-like object in the style of object-orientedprogramming(OOP).Thetype counter forcountersisdefinedasfollows:

typedef

counter='{

get=()-<cloref1>int

,inc=()-<cloref1>void

,reset=()-<cloref1>void

}//endof[counter]

The three fields of counter are closure functions that correspond to methods associated with anobject: getting the count of the counter, increasing the count of the counter by 1 and resetting thecountofthecounterto0.Thefollowingdefinedfunction newCounter isforcreatingacounterobject(representedasaboxedrecordofclosurefunctions):

funnewCounter

(

//argumentless

):counter=let

valcount=ref<int>(0)

in'{

get=lam()=>!count

,inc=lam()=>!count:=!count+1

,reset=lam()=>!count:=0

}end//endof[newCounter]

Thestateofeachcreatedcounterobjectisstoredinareference,whichcanonlybeaccessedbythethree closure functions in the record that represents the object. This is often referred to as stateencapsulationinOOP.

Imyself think that theabovecounter implementation isof ratherapoorstyle. It isalsopossible toprotecttheintegrityofastatebysimplymakingitabstract.Iwillpresentelsewhereanothercounterimplementationbasedonalinearabstracttype(thatis,abstractviewtypeinATS),wherecounterscanbecreatedandthensafelyfreed.

Page 114: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Arrays

Imentionedearlierthatareferenceisjustanarrayofsize1.Iwouldnowliketostatethatanarrayofsizenisjustnreferencesallocatedconsecutively.Thesereferencescanalsobecalledcells,andtheyarenumberedfrom0untiln-1,inclusive.

Givenanarrayofsizen,anintegerisavalidindexforthisarrayifitisanaturalnumberstrictlylessthann.Otherwise,theintegerisoutoftheboundsofthearray.ForanarraynamedA,theexpressionA[i]means to fetch the content of the cell inA that is numbered i if i is a valid index forA.TheexpressionA[i]canalsobeusedasaleftvalue.Forinstance,theassignment(A[i]:=exp)meanstoevaluateexptoavalueandthenstorethevalueintothecellinAthatisnumberediifiisavalidindex.

WhathappensiftheindexiinA[i]isinvalid,thatis,itisoutoftheboundsofthearrayA?Inthiscase,A[i]isreferredtoasout-of-boundsarraysubscriptionandevaluatingA[i]leadstoaraisedexceptionwheretheexceptionis ArraySubscriptExn() .Onesimpleandreliablewaytotellwhetheranintegerisavalidindexforagivenarrayistocompareitwiththesizeofthearrayatrun-time.GivenatypeT,thetype arrszref(T) isforanarraypairedwithitssizeinwhichelementsofthetypeTarestored.Iwilllooselyrefertovaluesofthetype arrszref(T) asarraysfromnowon.Incasethereisaclearneedtoavoidpotentialconfusion,Imayalsorefertothemasarray0-values.

Various functions and function templates on array0-values are declared in the file arrayref.sats,whichisautomaticallyloadedbyatsopt.Forinstance,threefunctiontemplatesandonepolymorphicfunctiononarraysaredepictedbythefollowinginterfaces:

//

fun{a:t@ype}//template

arrszref_make_elt

(asz:size_t,x:a):arrszrefa//arraycreation

//

//polymorphicfun:

//

funarrszref_get_size

{a:t@ype}(A:arrszrefa):size_t//sizeofanarray

//

fun{a:t@ype}//template

arrszref_get_elt_at(A:arrszrefa,i:size_t):a//A[i]

//

fun{a:t@ype}//template

arrszref_set_elt_at(A:arrszrefa,i:size_t,x:a):void//A[i]:=x

//

Page 115: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

As for programming with arrays that carry no size information, it is a topic to be covered afterdependenttypesareintroduced.

LikeinC,therearemanytypesofintegervaluesinATS.Thetype size_t isessentiallyforunsignedlong integers. The functions for converting between the type int and the type size_t areg0int2uint_int_size and g0uint2int_size_int .GivenatypeTandtwovalues asz and init ofthetypessize_t andT,respectively, arrszref_make_elt<T>(asz,init) returnsanarrayofthetype arrszref(T)suchthatthesizeofthearrayis asz andeachcellinthearrayisinitializedwiththevalue init .GivenanarrayAofthetype arrszref(T) forsomeT, arrszref_get_size(A) returnsthesizeofA,whichisofthetype size_t .Forconvenience, arrszref_get_size(A) canbewrittenas A.size() .Asforarrayaccessandupdate,thefunctions arrszref_get_elt_at and arrszref_set_elt_at canbecalled.Forconvenience,thebracketnotationcanbeusedtocallthesefunctions.

Inthefollowingprogram,thefunctiontemplate insertion_sort implementsthestandardinsertionsortonarrays:

fun{

a:t@ype

}insertion_sort

(

A:arrszref(a)

,cmp:(a,a)->int

):void=let

valn=g0uint2int_size_int(A.size())

funins(x:a,i:int):<cloref1>void=

ifi>=0then

(

ifcmp(x,A[i])<0

then(A[i+1]:=A[i];ins(x,i-1))elseA[i+1]:=x

//endof[if]

)elseA[0]:=x//endof[if]

//endof[ins]

funloop(i:int):<cloref1>void=

ifi<nthen(ins(A[i],i-1);loop(i+1))else()

//endof[loop]

in

loop(1)

end//endof[insertion_sort]

Thecomparisonfunction cmp shouldreturn1,-1,and0ifitsfirstargumentisgreaterthan,lessthanandequaltoitssecondone,respectively.

Page 116: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Notethattheentirecodeinthissectionplussomeadditionalcodefortestingisavailableon-line.

Page 117: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:OrderingPermutations

Givenanaturalnumbern,wewant toprintoutall thepermutationsconsistingof integers rangingfrom1ton,inclusive.Inaddition,wewanttoprintthemoutaccordingtothelexicographicorderingonintegersequences.Forinstance,wewantthefollowingoutputtobegeneratedwhennis3:

1,2,3

1,3,2

2,1,3

2,3,1

3,1,2

3,2,1

Letusfirstdefineafunctionasfollowsforprintingoutanarrayofintegers:

funprint_intarray

(A:arrszref(int)):void=let

valasz=g0uint2int_size_int(A.size())

//

//Theintegersaretobeseparatedbythestring[sep]

//

funloop(i:int,sep:string):void=

ifi<aszthen

(ifi>0thenprintsep;printA[i];loop(i+1,sep))

//endof[if]

in

loop(0,",")

end//endof[print_intarray]

Wenextimplementtwofunctions lrotate and rrotate forrearrangingtheelementsinagivenintegerarray:

funlrotate(

A:arrszrefint,i:int,j:int

):void=let

funlshift(

A:arrszrefint,i:int,j:int

):void=

ifi<jthen(A[i]:=A[i+1];lshift(A,i+1,j))

in

ifi<jthenlet

valtmp=A[i]inlshift(A,i,j);A[j]:=tmp

end//endof[if]

end//endof[lrotate]

Page 118: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

funrrotate(

A:arrszrefint,i:int,j:int

):void=let

funrshift(

A:arrszrefint,i:int,j:int

):void=

ifi<jthen(A[j]:=A[j-1];rshift(A,i,j-1))

in

ifi<jthenlet

valtmp=A[j]inrshift(A,i,j);A[i]:=tmp

end//endof[if]

end//endof[rrotate]

Whenappliedtoanarrayandtwovalidindexesiandjforthearraysuchthatiislessthanorequaltoj, lrotate movessimultaneouslythecontentofcelliintocelljandthecontentofcellktocellk-1forkrangingfromi+1toj,inclusive.Thefunction rrotate issimilarto lrotate butshuffleselementsintheoppositedirection.

Given a natural number n, the following defined function permute prints out all the permutationsconsisting of integers ranging from 1 to n, inclusivewhile arranging the output according to thelexicographicorderingonintegersequences.

funpermute

(n:int):void=let

//

#definei2szg0int2uint_int_size

//

//CreatingarrayAofsizen

//

valA=arrszref_make_elt<int>(i2sz(n),0)

//

//InitializingAwithintegersfrom1ton,inclusive

//

val()=init(0)where

{

funinit(i:int):void=

ifi<nthen(A[i]:=i+1;init(i+1))

}//endof[where]//endof[val]

//

funaux

(i:int):void=

(

ifi<=n

Page 119: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

thenaux2(i,i)

else(

print_intarray(A);print_newline()

)(*endof[else]*)

)(*endof[aux]*)

//

andaux2

(i:int,j:int):void=

(

ifj<=nthenlet

val()=(

rrotate(A,i-1,j-1);aux(i+1);lrotate(A,i-1,j-1)

)//endof[val]

in

aux2(i,j+1)

end//endof[if]

)(*endof[aux2]*)

//

in

aux(1)

end//endof[permute]

Notethat where isakeyword,andtheexpression(exp where { decseq } ) forsomeexpressionexpanddeclarationsequencedecseqisequivalenttothelet-expressionoftheform( let decseq in expend ).Tounderstandthebehaviorofthefunction aux ,letusevaluate aux(1) whileassumingthat n is4andthe4elementsofthearray A are1,2,3,and4.Itshouldbefairlystraightforwardtoseethatthisevaluationleadstotheevaluationof aux(2) for4times:thearray A contains(1,2,3,4)forthefirsttime,and(2,1,3,4) for thesecondtime,and(3,1,2,4) for the third time,and(4,1,2,3) for thefourth time.With some inductive reasoning, it shouldnotbedifficult to see that evaluating aux(1)indeedleadstoallthepermutationsbeingoutputaccordingtothelexicographicorderingonintegersequences.

Pleasefindtheentirecodeinthissectionplussomeadditionalcodefortestingon-line.

Page 120: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Matrices

AmatrixinATSisjustatwo-dimensionalarraybutitisrepresentedbyaone-dimensionalarrayandtherepresentationisoftherow-majorstyle(incontrasttothecolumn-majorstyle).GivenatypeT,thetype mtrxszref(T) isforamatrixcombinedwithitsnumberofrowsandnumberofcolumnssuchthat each element stored in the matrix is of the type T. I will loosely refer to values of the typemtrxszref(T) asmatricesfromnowon.Ifthereisaclearneedtoavoidpotentialconfusion,Imayalsorefertothemasmatrix0-values.

GivenamatrixMofdimensionmbyn,theexpressionM[i,j]meanstofetchthecontentofthecellinMthatisindexedby(i,j),whereiandjarenaturalnumbersstrictlylessthanmandn,respectively.The expressionM[i,j] can alsobeused as a left value.For instance, the assignment (M[i,j] := exp)meanstoevaluateexptoavalueandthenstorethevalueintothecellinMthatisindexedby(i,j).

Various functions and function templates onmatrix0-values are declared in the filematrixref.sats,whichisautomaticallyloadedbyatsopt.Forinstance,threefunctiontemplatesandtwopolymorphicfunctionsonmatricesaredepictedbythefollowinginterfaces:

fun{a:t@ype}

mtrxszref_make_elt//template

(row:size_t,col:size_t,x:a):mtrxszref(a)

funmtrxszref_get_nrow{a:t@ype}(M:mtrxszrefa):size_t//polyfun

funmtrxszref_get_ncol{a:t@ype}(M:mtrxszrefa):size_t//polyfun

fun{a:t@ype}

mtrxszref_get_elt_at//template

(M:mtrxszrefa,i:size_t,j:size_t):a//M[i,j]

fun{a:t@ype}

mtrxszref_set_elt_at//template

(M:mtrxszrefa,i:size_t,j:size_t,x:a):void//M[i,j]:=x

GivenatypeTandthreevalues nrow , ncol and init ofthetypes size_t , size_t andT,respectively,mtrxszref_make_elt<T> (row, col, init) returns a matrix of the type mtrxszref(T) such that thedimensionofthematrixis nrow by ncol andeachcellinthematrixisinitializedwiththevalue init .Given a matrix M of the type mtrxszref(T) for some T, mtrxszref_get_nrow(M) andmtrxszref_get_ncol(M) return the number of rows and the number of columns of M, respectively,whicharebothofthetype size_t .Forconvenience, mtrxszref_get_nrow(M) and mtrxszref_get_ncol(M)canalsobewrittenas M.nrow and M.ncol ,respectively.Asformatrixaccessandupdate,thefunction

Page 121: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

templates mtrxszref_get_elt_at and mtrxszref_set_elt_at canbecalled,respectively.Forconvenience,bracketnotationcanusedforthesefunctions.

Let us now take a look at an example. The following defined function mtrxszref_transpose turns agivenmatrixintoitstranspose:

fun{a:t@ype}

mtrxszref_transpose

(M:mtrxszrefa):void=let

//

valnrow=mtrxszref_get_nrow(M)

//

fnxloop1

(i:size_t):void=

ifi<nrowthenloop2(i,0)else()

//

andloop2

(i:size_t,j:size_t):void=

ifj<ithenlet

valtmp=M[i,j]

in

M[i,j]:=M[j,i];M[j,i]:=tmp;loop2(i,j+1)

endelse

loop1(i+1)

//endof[if]

//

in

loop1(0)

end//endof[mtrxszref_transpose]

ThematrixMisassumedtobeasquare, that is, itsnumberofrowsequals itsnumberofcolumns.Note that the twofunctions loop1 and loop2 aredefinedmutually tail-recursively,and thekeywordfnx indicatestheneedtocombinethebodiesof loop1 and loop2 sothatmutualrecursivetail-callsinthesefunctionbodiescanbecompiledintodirectlocaljumps.

Page 122: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:EstimatingtheConstantPi

I present as follows a Monte Carlo approach to estimating the constant Pi, the ratio of thecircumferenceofacircleoveritsdiameter.

AssumethatwehaveasquareofthedimensionNbyN,whereNisarelativelylargenaturalnumber(e.g.,1000),andadiskofradius1thatiscontainedinthesquare.LetN2standforN*N,thatis, thesquareofN.Ifwerandomlychooseapointinsidethesquare,thentheprobabilityforthepointtohitthediskisPi/N2.

The experiment we use to estimate the constant Pi can be described as follows. Given a naturalnumberK,letusrandomlychooseKpointsinsidethesquareinKrounds.Ineachround,wechooseexactlyonepoint.Ifthepointchoseninroundkhitsonthediskcenteredatapreviouslychosenpoint,thenwerecordonehit.Clearly,theexpectednumberofhitsrecordedinroundkis(k-1)*Pi/N2ask-1pointshavealreadybeingchoseninthepreviousrounds.Therefore,inKrounds,theexpectedtotalnumberofhitsis(K*(K-1)/2)*Pi/N2.IfKisfixedtobeN2,thentheexpectedtotalnumberofhitsis(N2-1)*Pi/2. It can be proven that the total number of hits divided byN2 converges to Pi/2 (withprobability1)asNapproachesinfinity.

Ifweimplementtheaboveexperimentdirectlybasedonthegivendescription,thetime-complexityoftheimplementationisevidentlyproportionaltoN2*N2asthetimespentinroundkisproportionaltok,where k ranges from1 toN2.An implementation as such is simply impractical for handlingNaround the order 1000 (and thusN2 around the order of 1,000,000). To address the issue,we canimpose a grid on the square, dividing it intoN2 unit squares (of the dimension 1 by 1).We thenassociatewitheachunitsquarealistofchosenpointsthatareinsideit.Ineachround,wefirstchooseapointrandomlyinsidetheoriginalsquare;wenextlocatetheunitsquarethatcontainsthispoint;wethenonlysearchthelistsassociatedwiththeunitsquareoranyofitsneighborstocountthenumberofhitsgeneratedbythepointchoseninthisroundasthispointcannothitanydiskscenteredatpointsthatarenotontheselists.Aseachunitsquarecanhaveatmost8neighborsandtheaveragelengthofthe listassociatedwitheachsquare is less than1during theexperiment, the timespentduringeachroundisO(1),thatis,boundedbyaconstant.Hence,thetimetakenbytheentireexperimentisO(N2).

Animplementation thatpreciselymatches theabovedescriptionplussometestingcode isavailableon-line.

Page 123: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

SimpleInputandOutput

Handling I/O in ATS properly requires the availability of both dependent types and linear types,whichIwillcoverelsewhere.Inthissection,IonlypresentameansforallowingtheprogrammertoaccesscertainverybasicI/Ofunctionalities.

Afilehandleessentiallyassociatesastream(ofbytes)withafileidentifier(representedasaninteger).InATS,thetypeforfilehandlesis FILEref .Therearethreestandardfilehandles,whicharelistedasfollows:

stdin_ref :standardinput

stdout_ref :standardoutput

stderr_ref :standarderroroutput

Variousfunctionsonfilehandlesaredeclaredinthefilefilebas.sats,whichisautomaticallyloadedby atsopt. For instance, the functions for opening and closing file handles have the followinginterfaces:

funfileref_open_exn

(

path:string,fm:file_mode

):FILEref//endfun

funfileref_close(fil:FILEref):void

Notethatthesetwofunctionsabortimmediatelywheneveranerroroccurs.Thefollowingfunctionisanoptionalversionof fileref_open_exn ,andthecallerneedstoinspectthevaluereturnedbyacalltofileref_open_opt toseeifafilehandleisactuallyobtained.

funfileref_open_opt

(path:string,fm:file_mode):Option_vt(FILEref)

Thetype file_mode isforvaluesrepresentingfilemodes,whicharelistedasfollows:

file_mode_r :openingafileforreadingandpositioningtheassociatedstreamatthebeginningofthefile.

file_mode_rr : opening a file for both reading and and writing and positioning the associated

Page 124: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

streamatthebeginningofthefile.

file_mode_w : truncating a given file to zero length or creating a new one for writing andpositioningtheassociatedstreamatthebeginningofthefile.

file_mode_ww :truncatingagivenfiletozerolengthorcreatinganewoneforbothreadingandwritingandpositioningtheassociatedstreamatthebeginningofthefile.

file_mode_a : openinga file forwritingandpositioning theassociated streamat theendof thefile.

file_mode_aa :openingafileforbothreadingandwritingandpositioningtheassociatedstreamatthebeginningofthefileforreadingandattheendforwriting.

Asanexample, thefollowingshortprogramopensafilehandle,outputs thestring"Hello,world!"plusanewlineintothestreamassociatedwiththefilehandleandthenclosesthefilehandle:

implement

main0()=

{

valout=

fileref_open_exn("hello.txt",file_mode_w)

val()=fprint_string(out,"Hello,world!\n")

val()=fileref_close(out)

//

}(*endof[main0]*)

Afterexecutingtheprogram,weobtainafileofthename"hello.txt"inthecurrentworkingdirectorycontainingtheexpectedcontent.Therearevariousfprint-functionsinATSforprintingoutdataintothestreamassociatedwithagivenfilehandle.Oftentheprogrammercansimplyusethename fprinttorefertothesefunctionsduetothesupportforoverloadinginATS.

AnothercommonI/Ofunctionisgiventhefollowinginterface:

funfileref_get_line_string(fil:FILEref):Strptr1

Thefunction fileref_get_line_string readsalinefromthestreamassociatedwithagivenfilehandle,anditreturnsavalueofthetype Strptr1 .Forthemoment,Iwillsimplysaythatsuchavalueisjustlikeastringexcept that itneedstobefreedexplicitly.Asanexample, thefollowingshortprogramechosontothestandardoutputeachlinereadfromthestandardinput:

Page 125: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

implement

main0(

//argumentless

)=loop()where

{

//

funloop():void=let

valisnot=fileref_isnot_eof(stdin_ref)

in

//

ifisnotthenlet

valline=

fileref_get_line_string(stdin_ref)

val((*void*))=fprintln!(stdout_ref,line)

val((*void*))=strptr_free(line)

in

loop()

endelse((*loopexitsastheend-of-fileisreached*))

//

end(*endof[loop]*)

//

}(*endof[main0]*)

Notethatthefunction strptr_free iscalledtofreealinearstring(ofthetype Strptr1 ).Often,typingtheCTRL-Dcharactercanterminatetheaboveprogramforechoingeachlineofinput.

Page 126: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 127: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 128: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter7.ModularityGenerallyspeaking,modularityinprogrammingmeanstoorganizeprogramsinamodularfashionsothattheyeachcanbeconstructedinarelativelyisolatedmannerandthenbecombinedtofunctioncoherently.IwillintroduceinthissectionsomefeaturesinATSthatarelargelydesignedtofacilitateprogramorganization.

Thecodeemployedforillustrationinthischapterplussomeadditionalcodefortestingisavailableon-line.

Page 129: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

TypesasaFormofSpecification

Theinterfaceforafunctionorvaluespecifiesatypethatanyimplementationofthefunctionorvalueshouldpossess.Forinstance,thefollowingcodedefinesafunction fact forcomputingthefactorialofagiveninteger:

funfact(x:int):int=ifx>0thenx*fact(x-1)else1

Itisalsopossibletofirstdeclareaninterfacefor fact asfollows:

externfunfact(x:int):int

where extern isakeyword inATS that initiates thedeclarationofan interface.Alternativeways todeclareaninterfacefor fact aregivenasfollows:

externfunfact:(int)->int

externvalfact:(int)->int

If fact isdeclaredtobeafunction,thenitisrequiredtobeappliedwhenoccurringincode.Ifitisdeclaredtobeavalue,thereisnosucharestriction.

Afunction interfacecanbeconsideredasa formofspecification.For instance, theabove interfacefor fact specifiesthat fact isafunctionthattakesoneargumentrequiredtobeanintegerandreturnsavalueguaranteed tobean integer.What is so special about this formof specification is that it isformally enforced in ATS through typechecking: Any well-typed implementation of fact in ATSmust possess the interface declared for it. Of course, this interface for fact is not a precisespecificationasthereare(infinitely)manyfunctionsthatcanbegiventhesameinterface.Thiskindofimprecision can, however, be reduced or even eliminated, sometimes. After dependent types areintroduced, I will present an interface for fact such that any implementation of the interface isguaranteedtoimplementpreciselythefactorialfunctionasisdefinedbythefollowingtwoequations:

fact(0)=1

fact(n)=n*fact(n-1)foreachnaturalnumbern>0

An implementation for fact as the following one can be given at any point where the declaredinterfacefor fact isaccessible:

implementfact(x)=ifx>0thenx*fact(x-1)else1

Page 130: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Thekeyword implement isforinitiatinganimplementationofafunctionorvaluewhoseinterfaceisalreadydeclared. It is fairlycommon to see the followingstyleofcoding,usually,byabeginningATSprogrammer:

implementfact(x:int):int=ifx>0thenx*fact(x-1)else1

Whilethisimplementationcanpasstypechecking,itisnonethelessofapoorstyle:Thetypesprovidedbytheprogrammerfortheargumentandtheresultof fact areredundantastheycanbeautomaticallysynthesizedbythetypechecker.

Asanexampleofaninterfaceforavalue, fact10 isdeclaredasfollowstobeavalueofthetype int :

externvalfact10:int

Thefollowingimplementationfor fact10 canbegivenatanypointwherethedeclaredinterfaceforfact10 isaccessible:

implementfact10=fact(10)

As another example, the following code declares an interface for a polymorphic function namedswap_boxed :

extern

funswap_boxed{a,b:type}(xy:(a,b)):(b,a)

Note that both type variables a and b are boxed. An implementation for swap_boxed is given asfollows:

implementswap_boxed{a,b}(xy)=(xy.1,xy.0)

Thesyntax {a,b} isforpassingstaticarguments a and b to swap_boxed simultaneously.Asneither anor b isactuallyusedinthebodyof swap_boxed ,itisallowedtodrop {a,b} inthiscase.

As yet another example, the following code declares an interface for a function template namedswap_tmplt :

extern

fun{a,b:t@ype}swap_tmplt(xy:(a,b)):(b,a)

Notethatbothtypevariables a and b areofthesort t@ype ,indicatingthattheycanbeofanysize.An

Page 131: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

implementationfor swap_tmplt isgivenasfollows:

implement{a,b}swap_tmplt(xy)=(xy.1,xy.0)

Itisastandardpracticeforaprogrammertofirstdesigninterfacesforthefunctionstobesupportedinapackagebeforeactuallyimplementinganyofthesefunctions.Whensuchinterfacesareavailable,application programs can be constructed to test whether the interface design makes sense or isconvenientforpracticaluse.Pleaserememberthatasuperbimplementationofapoordesigncannotmake the design anybetter.Therefore, testing a designbefore actually implementing it is often ofvitalimportance.Thisisespeciallytrueiftheinvolveddesigniscomplex.

Page 132: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

StaticandDynamicATSFiles

ThefirstlettersintheATSfilenameextensionssatsanddatsrefertothewordsstaticanddynamic,respectively.Forinstance,foo.satsisanameforastaticfilewhilebar.datsisforadynamicone.A

static file is often referred to as a SATS-file, and it usually contains interface declarations forfunctionsandvalues,datatypedeclarations,typedefinitions,etc.TheprimarypurposeofaSATS-fileisforallowingitscontenttobesharedamongvariousotherATSfiles,eitherstaticordynamic.

Letusnowgothroughasimpleexampletoseeatypicaluseofstaticfiles.Supposethatwewanttoimplement the Ackermann's function, which is famous for being recursive but not primitiverecursive. In a static file named acker.sats (or any other legal filename), we can declare the

followingfunctioninterface:

funacker(m:int,n:int):int

Please note that one should not use the keyword extern when declaring an interface for either afunction or a value in a static file. Then in a dynamic file namedacker.dats (or any other legal

filename),wecangivethefollowingimplementation:

staload"acker.sats"

implement

acker(m,n)=

ifm>0then

ifn>0thenacker(m-1,acker(m,n-1))

elseacker(m-1,1)

elsen+1

//endof[acker]

Thekeyword staload indicates to theATS typechecker that the file following it is to be staticallyloadedduringtypechecking.Essentially,staticallyloadingafilemeanstoputthecontentofthefileinanamespacethatcanbeaccessedbythefollowingcode.Itisimportanttonotethatstaticloadingisdifferentfromplainfileinclusion.ThelatterisalsosupportedinATS,anditisafeatureIwillcoverelsewhere.

Itisalsopossibletogivethefollowingimplementationforthedeclaredfunction acker :

staloadACKER="acker.sats"

implement$ACKER.acker

Page 133: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

(m,n)=acker(m,n)where{

funacker(m:int,n:int):int=

ifm>0then

ifn>0thenacker(m-1,acker(m,n-1))

elseacker(m-1,1)

elsen+1

}//endof[$ACKER.acker]

Inthiscase,thenamespaceforstoringthecontentofthefileacker.satsisgiventhenameACKER,

and the prefix $ACKER. (the dollar sign followed byACKER followed by the dot symbol)must beattached toanyname that refers anentity (a function, avalue, adatatype, a constructor (associatedwithadatatype),atypedefinition,etc.)declaredinacker.sats.Whentherearemanystaticfilestobe

loaded, it isoftenagoodpracticetoassignnamestothenamespacesholdingthesefilessothat theoriginalsourceofeachdeclaredentitycanbereadilytrackeddown.

Inanotherfilenamedtest_acker.dats,letuswritethefollowingcode:

//

#include

"share/atspre_staload.hats"

//

staload"acker.sats"

dynload"acker.dats"

implement

main0()=()where{

//

//acker(3,3)shouldreturn61

//

val()=assertloc(acker(3,3)=61)

}//endof[main0]

The keyword dynload indicates to theATS compiler to generate a call to the initializing functionassociatedwith thefileacker.dats.This ismandatoryasanerrorwouldotherwisebe reportedat

link-time.Usually,callingtheinitializingfunctionassociatedwithadynamicfileisnecessaryonlyifthere is a value implemented in the file. In this case, there is only a function implemented inacker.dats.Ifweincludethefollowinglinesomewhereinsideacker.dats:

#defineATS_DYNLOADFLAG0//noneedfordynloadingatrun-time

then the line starting with the keyword dynload in test_acker.dats is no longer needed. The

Page 134: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

function assertloc verifiesat run-time that itsargumentevaluates to thebooleanvalue true . In thecasewheretheargumentevaluates to false , the functioncallabortsandamessage is reported thatcontainsthenameofthefile,whichistest_acker.datsinthisexample,andthelocationatwhichthe

source code of the call is found in the file. If this sounds a bit confusing, please try to execute aprogramthatcontainsacallto assertloc on false andyouwillseeclearlywhathappens.

The simplest way to compile the two files acker.dats and test_acker.dats is to issue the

followingcommand-line:

atscc-otest_ackeracker.datstest_acker.dats

Thegeneratedexcutabletest_ackerisinthecurrentworkingdirectory.Thecompilationcanalsobe

performedseparatelyasisdemonstratedbelow:

atscc-cacker.dats

atscc-ctest_acker.dats

atscc-otest_ackeracker_dats.otest_acker_dats.o

Thisstyleofseparatecompilationworksparticularlywellwhenitisemployedbythemakeutility.

Ifwewantto,wecanalsomergeacker.satsandacker.datsintoasinglefilenameofthefollowing

content:

extern

funacker(m:int,m:int):int

implement

acker(m,n)=

ifm>0then

ifn>0thenacker(m-1,acker(m,n-1))

elseacker(m-1,1)

elsen+1

//endof[acker]

Supposethatthissinglefileisgiventhenameacker3.dats.Thenthetestingcodecanbewrittenas

follows:

//

#include

"share/atspre_staload.hats"

//

staload"acker3.dats"

Page 135: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

dynload"acker3.dats"

implement

main0()=()where{

//

//acker(3,3)shouldreturn61

//

val()=assertloc(acker(3,3)=61)

}//endof[main0]

NotethatitisperfectlyfineforadynamicATSfiletobestaticallyloaded.Actually,astaticATSfileisreallyjustaspecialcaseofdynamicATSfileinwhichthereisnoimplementation(ofeitherfunctionsorvalues).

Page 136: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

GenericTemplateImplementation

Interfaces for function templates are mostly similar to those for functions. For example, thefollowing syntax declares an interface in a dynamic file for a function template of the namelist0_fold_left :

extern

fun{

a:t0p}{b:t0p

}list0_fold_left

(xs:list0b,f:(a,b)-<cloref1>a,init:a):a

where t0p isashorthandfor t@ype .

Ifthesameinterfaceisdeclaredinastaticfile,thekeyword extern shouldbedropped.Implementingan interfacefora function template isalsomostlysimilar to implementingonefora function.Theaboveinterfacefor list0_fold_left isgivenanimplementationinthefollowingcode:

implement{a}{b}

list0_fold_left

(xs,f,init)=let

//

funloop

(

xs:list0b,res:a

):a=

(

case+xsof

|list0_nil()=>res

|list0_cons(x,xs)=>loop(xs,f(res,x))

)(*endof[loop]*)

//

in

loop(xs,init)

end//endof[list0_fold_left]

Note that templateparametersare required toappear immediatelyafter thekeyword implement ,andthey cannot be omitted. Template parameters can also be passed sequentially as is shown in thefollowingshortexample:

extern

fun

{a,b:t0p}{c:t0p}

Page 137: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

app2(f:(a,b)-<cloref1>c,x:a,y:b):c

implement{a,b}{c}app2(f,x,y)=f(x,y)

The style of template implementation presented in this section is referred to as generic templateimplementation. I will later present a different style of template implementation, which is oftenreferredtoasspecifictemplateimplementation.

Page 138: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

SpecificTemplateImplementation

Implementinganinterfaceforafunctiontemplatespecificallymeanstogiveanimplementationforafixedinstanceofthetemplate.Forinstance,thefollowinginterfaceisforafunctiontemplateofthename eq_elt_elt :

fun{a:t0p}

eq_elt_elt(x:a,y:a):bool//agenericequality

Thereisnomeaningfulgenericimplementationfor eq_elt_elt asequalitytestforvaluesofatypeTdepends on T. Two specific template implementations are given as follows for the instanceseq_elt_elt<int> and eq_elt_elt<double> :

implementeq_elt_elt<int>(x,y)=g0int_eq(x,y)

implementeq_elt_elt<double>(x,y)=g0float_eq(x,y)

where eq_int_int and eq_double_double areequalityfunctionsforvaluesofthetype int and double ,respectively.Itisalsopossibletogivetheimplementationsasfollows:

implementeq_elt_elt<int>(x,y)=(x=y)

implementeq_elt_elt<double>(x,y)=(x=y)

Thisisallowedasthesymbol = isalreadyoverloadedwith g0int_eq and g0float_eq (inadditiontomanyotherfunctions).

Let us now see a typical use of specific template implementation. The following defined functiontemplate listeq implementsanequalityfunctiononlists:

fun{

a:t0p

}listeq

(

xs:list0a

,ys:list0a

):bool=(

case+(xs,ys)of

|(list0_cons(x,xs),

list0_cons(y,ys))=>

ifeq_elt_elt<a>(x,y)thenlisteq(xs,ys)elsefalse

|(list0_nil(),list0_nil())=>true

|(_,_)=>false

)(*endof[listeq]*)

Page 139: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Giventwolistsxsandys, listeq returns true ifandonlyifxsandysareofthesamelengthandeachelementinxsequalsthecorrespondingoneinys(accordingto eq_elt_elt ).GivenatypeT,itisclearthattheinstance eq_elt_elt<T> isneededif listeq iscalledontwolistsofthetype list0(T) .Inotherwords,aspecificimplementationfor eq_elt_elt<T> shouldbegivenifacallto listeq istobemadeontwolistsofthetype list0(T) .Notethattheimplementationforaninstanceofafunctiontemplateisrequiredtobeaccessiblefromthefilewheretheinstanceiscalled.

Asacomparison, thefollowingdefinedfunction template listeqf also implementsequality testontwogivenlists:

fun{

a:t0p

}listeqf

(

xs:list0a

,ys:list0a

,eq:(a,a)->bool

):bool=(

case+(xs,ys)of

|(list0_cons(x,xs),

list0_cons(y,ys))=>

ifeq(x,y)thenlisteqf(xs,ys,eq)elsefalse

|(list0_nil(),list0_nil())=>true

|(_,_)=>false

)(*endof[listeqf]*)

Inthiscase, listeqf takesanadditionalargument eq thattestswhethertwolistelementsareequal.Aslisteq isafirst-orderfunctionwhile listeqf isahigher-orderone,itislikelyfortheformertobecompiled intomore efficient object code. Iwould like to point out that the library ofATSmakespervasiveuseofspecificallyimplementedtemplates.

Pleasefindthecodepresentedinthissectionplussomeadditionaltestingcodeavailableon-line.

Page 140: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

AbstractTypes

Thenameabstracttype refers toa typesuchthatvaluesof thetypearerepresentedinawaythat iscompletelyhidden fromusersof the type.This formof information-hidingattempts to ensure thatchangestotheimplementationofanabstracttypecannotintroducetype-errorsintowell-typedcodethatmakesuseoftheabstracttype.InATSaswellasinmanyotherprogramminglanguages,abstracttypesplayapivotal role in supportofmodularprogramming. Iwillpresent as followsaconcreteexampletoillustrateatypicaluseofabstracttypesinpractice.

Suppose that we are to implement a package to provide various funtionalities on finite sets ofintegers.We first declare an abstract type intset as follows for values representing finite sets ofintegers:

abstypeintset//aboxedabstracttype

The keyword abstype indicates that the declared abstract type intset is boxed, that is, the size ofintset isthesameasthatofapointer.Thereisarelatedkeyword abst@ype forintroducingunboxedabstracttypes,whichwillbeexplainedelsewhere.Wenextpresentaninterfaceforeachfunctionorvaluethatwewanttoimplementinthepackage:

//emptyset

valintset_empty:intset

//singletonsetof[x]

funintset_make_sing(x:int):intset

//turningalistintoaset

funintset_make_list(xs:list0int):intset

//turningasetintoalist

funintset_listize(xs:intset):list0(int)

//membershiptest

funintset_ismem(xs:intset,x:int):bool

//computingthesizeof[xs]

funintset_size(xs:intset):size_t

//adding[x]into[xs]

funintset_add(xs:intset,x:int):intset

//deleting[x]from[xs]

Page 141: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

funintset_del(xs:intset,x:int):intset

//unionof[xs1]and[xs2]

funintset_union(xs1:intset,xs2:intset):intset

//intersectionof[xs1]and[xs2]

funintset_inter(xs1:intset,xs2:intset):intset

//differencebetween[xs1]and[xs2]

funintset_differ(xs1:intset,xs2:intset):intset

Letusnowsuppose that thedeclaration for intset and theabove interfacesareall stored ina filenamedintset.sats(oranyotherlegalnameforastaticfile).

Usually,arealisticimplementationforfinitesetsisbasedonsomekindofbalancedtrees(e.g.,AVLtrees,red-blacktrees).Forthepurposeofillustration,Iherebygiveanimplementationinwhichfinitesetsofintegersarerepresentedasorderedlistsofintegers.Thisimplementationiscontainedinafilenamedintset.dats,whichisavailableon-line.Inordertoconstructvaluesofanabstract type,we

needtoconcretizeittemporarilybyusingthefollowingformofdeclaration:

assumeintset=list0(int)

where assume isakeyword.Thisassume-declarationequates intset withthetype list0(int) andthisequationisvaliduntiltheendofthescopeinwhichitisintroduced.Astheassume-declarationisatthetoplevelinintset.dats,theassumptionthat intset equals list0(int) isvaliduntil theendof

the file.There is aglobal restriction inATS that allowseachabstract type tobeconcretizedbyanassume-declaration at most once.More specifically, if an abstract type is concretized in two filesfoo1.datsandfoo2.dats,thenthesetwofilescannotbeusedtogethertogenerateanexecutable.The

restofimplementationin intset isallstandard.Forinstance,theunionoperationontwogivensetsofintegersisimplementedasfollows:

implement

intset_union

(xs1,xs2)=(

case+(xs1,xs2)of

|(list0_cons(x1,xs11),

list0_cons(x2,xs21))=>

let

valsgn=compare(x1,x2)

in

case+0of

Page 142: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

|_whensgn<0=>

list0_cons{int}(x1,intset_union(xs11,xs2))

|_whensgn>0=>

list0_cons{int}(x2,intset_union(xs1,xs21))

|_(*sgn=0*)=>

list0_cons{int}(x1,intset_union(xs11,xs21))

//endof[case]

end//endof[(cons,cons)]

|(list0_nil(),_)=>xs2

|(_,list0_nil())=>xs1

)(*endof[intset_union]*)

There is also some testing code available on-line that makes use of some functions declared inintset.sats.Often testingcodeassuch isconstructed immediatelyafter the interfacesforvarious

functionsandvaluesinapackagearedeclared.Thisallowstheseinterfacestobetriedbeforetheyareactuallyimplementedsothatpotentialflawscanbeexposedinatimelyfashion.

Page 143: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:APackageforRationals

Letusrepresentarationalnumberasapairofintegers.Ifwedeclareaboxedabstracttype rat forvalues representing rational numbers, then each value of the type rat is stored in heap-allocatedmemory, which can only be reclaimed through garbage collection (GC). Instead, we follow analternativeapproachbydeclaring rat asanunboxedabstracttype.Therefore,adeclarationlikethefollowingoneisexpected:

abst@yperat

Theproblemwiththisdeclarationisthatitistooabstract.Asthereisnotinformationgivenaboutthesizeofthetype rat ,theATScompilerdoesnotevenknowhowmuchmemoryisneededforstoringavalueofthetype rat .However,theprogrammershouldnotassumethatsuchaformofdeclarationis useless. There are realistic circumstances where a declaration of this form can be of greatimportance,andthisisatopicIwillcoverelsewhere.Fornow,letusdeclareanunboxedabstracttypeasfollows:

abst@yperat=(int,int)

ThisdeclarationsimplyinformstheATScompilerthattherepresentationforvaluesofthetype rat isthesameastheoneforvaluesofthetype (int,int) .However,thisinformationisnotmadeavailabletothetypecheckerofATS.Inparticular,ifavalueofthetype rat istreatedasapairofintegersinaprogram,thenatype-errorwillsurelyoccur.

Thefollowingcodeiscontainedinafilenamedratmod.sats,whichisavailableon-line.

exceptionDenominator

exceptionDivisionByZero

funrat_make_int_int(p:int,q:int):rat

funratneg:(rat)->rat//negation

funratadd:(rat,rat)->rat//addition

funratsub:(rat,rat)->rat//subtraction

funratmul:(rat,rat)->rat//multiplication

funratdiv:(rat,rat)->rat//division

Theexception Denominator isforreportinganerroneousoccasionwherearationalnumberistobeformed with a denominator equal to zero. Given two integers representing the numerator and

Page 144: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

denominator of a rational number, the function rat_make_int_int returns a value representing therational number. The following implementation of rat_make_int_int can be found in a file namedratmod.dats,whichisalsoavailableon-line.

implement

rat_make_int_int(p,q)=let

funmake(

p:int,q:int

):rat=let

valr=gcd(p,q)in(p/r,q/r)

end//endof[make]

//

val()=ifq=0then$raiseDenominator

//

in

ifq>0thenmake(p,q)elsemake(~p,~q)

end//endof[rat_make_int_int]

Givenapairofintegerspandqsuchthatqisnotzero,thefunction rat_make_int_int returnsanotherpair of integers p1 and q1 such that q1 is positive, p1 and q1 are coprimes, that is, their greatestcommondivisoris1,andp1/q1equalsp/q.With rat_make_int_int ,itisstraightforwardtoimplementasfollowsthearithmeticoperationsonrationalnumbers:

implementratneg(x)=(~x.0,x.1)

implement

ratadd(x,y)=

rat_make_int_int(x.0*y.1+x.1*y.0,x.1*y.1)

//endof[ratadd]

implement

ratsub(x,y)=

rat_make_int_int(x.0*y.1-x.1*y.0,x.1*y.1)

//endof[ratsub]

implement

ratmul(x,y)=rat_make_int_int(x.0*y.0,x.1*y.1)

implement

ratdiv(x,y)=(

ify.0>0

thenrat_make_int_int(x.0*y.1,x.1*y.0)else$raiseDivisionByZero()

//endof[if]

)(*endof[ratdiv]*)

Page 145: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

There is also some testing code available on-line that makes use of some functions declared inratmod.sats.

Page 146: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:AFunctorialPackageforRationals

Thepreviouspackage for rationalnumberscontainsa serious limitation:The type for the integersemployedintherepresentationofrationalnumbersisfixedtobe int . Ifweeverwant torepresentrationalnumbersbasedonintegersofadifferenttype(forinstance, lint forlongintegersor llintfor long long integers), then we need to implement another package for rationals based on suchintegers.Itisclearlyadvantageoustoavoidthisstyleofprogrammingasitinvolvescodeduplicationtoagreatextent.

TheapproachIemployinthissectiontoimplementapackageforrationalnumbersthatcanaddressthe aforementioned limitation follows the idea of functors in the programming languageStandardML(SML).Letusfirstintroduceatypedefinitionasfollows:

typedef

intmod(a:t@ype)='{

ofint=int->a

,fprint=(FILEref,a)->void

,neg=(a)->a//negation

,add=(a,a)->a//addition

,sub=(a,a)->a//subtraction

,mul=(a,a)->a//multiplication

,div=(a,a)->a//division

,mod=(a,a)->a//modulooperation

,cmp=(a,a)->int//comparison

}//endof[intmod]

GivenatypeT, intmod(T) isaboxedrecordtypeinwhicheachfieldisafunctiontype.Avalueofthetype intmod(T) is supposed to represent amoduleof integeroperationson integers representedbyvaluesofthetypeT.Similarly,letusintroduceanothertypedefinitionasfollows:

abst@yperat(a:t@ype)=(a,a)

typedef

ratmod(a:t@ype)='{

make=(a,a)-<cloref1>rata

,fprint=(FILEref,rata)-<cloref1>void

,numer=rata->a//numerator

,denom=rata->a//denominator

,neg=(rata)-<cloref1>rata//negation

,add=(rata,rata)-<cloref1>rata//addition

,sub=(rata,rata)-<cloref1>rata//subtraction

,mul=(rata,rata)-<cloref1>rata//multiplication

Page 147: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

,div=(rata,rata)-<cloref1>rata//division

,cmp=(rata,rata)-<cloref1>int//comparison

}//endof[ratmod]

GivenatypeT,avalueofthetype ratmod(T) issupposedtorepresentamoduleofrationaloperationsonrationalsrepresentedbyvaluesofthetype rat(T) .Thefunctionweneedtoimplementcannowbegiventhefollowinginterface:

fun{a:t@ype}ratmod_make_intmod(int:intmoda):ratmoda

Ifapplied toagivenmoduleof integeroperations, ratmod_make_intmod returnsamoduleof rationaloperationssuch that the integers in theformerand the lattermoduleshave thesamerepresentation.Therefore, ratmod_make_intmod behaveslikeafunctorinSML.Inthefollowingcode,letusimplementtwomodules ratmod_int and ratmod_dbl of rationaloperations inwhich integersare representedasvaluesofthetypes int and double ,respectively:

staloadM="libc/SATS/math.sats"

valratmod_int=let

//

valintmod_int='{

ofint=lam(i)=>i

,fprint=lam(out,x)=>$extfcall(void,"fprintf",out,"%i",x)

,neg=lam(x)=>~x

,add=lam(x,y)=>x+y

,sub=lam(x,y)=>x-y

,mul=lam(x,y)=>x*y

,div=lam(x,y)=>x/y

,mod=lam(x,y)=>opmod(x,y)

,cmp=lam(x,y)=>compare(x,y)

}:intmod(int)//endof[val]

//

in

ratmod_make_intmod<int>(intmod_int)

end//endof[val]

valratmod_dbl=let

//

valintmod_dbl='{

ofint=lam(i)=>g0i2f(i)

,fprint=lam(out,x)=>$extfcall(void,"fprintf",out,"%0.f",x)

,neg=lam(x)=>~x

,add=lam(x,y)=>x+y

,sub=lam(x,y)=>x-y

Page 148: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

,mul=lam(x,y)=>x*y

,div=lam(x,y)=>$M.trunc(x/y)//truncation

,mod=lam(x,y)=>$M.fmod(x,y)

,cmp=lam(x,y)=>compare(x,y)

}:intmod(double)//endof[val]

//

in

ratmod_make_intmod<double>(intmod_dbl)

end//endof[ratmod_dbl]

Animplementationof thefunction ratmod_make_intmod isavailableon-lineand there issomerelatedtestingcodeavailableon-lineaswell.

Page 149: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 150: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 151: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter8.InteractionwithCATSandCsharepreciselythesamenative/flat/unboxeddatarepresentation.Asaconsequence,thereis no need for wrapping/unwrapping or boxing/unboxing when calling from C a functionimplementedinATSorviceversa,andthereisalsonorun-timeoverheadfordoingso.Toalargeextent,ATScanbeconsideredafront-endtoCthatisequippedwithahighlyexpressivetypesystem(for specifying program invariants) and a highly adaptable template system (for facilitating codereuse). In particular, ATS can often be effectively employed to turn a large task into subtasks ofcoherent interfaces, which can be implemented in ATS, C or some other langauges and thenassembledtogethertoformasolutiontotheorginaltask.

Ascanbeexpected,Ccode thatappearsdirectly inATSdoesnotgo through thekindof rigoroustypechecking likeATS code should. So it is recommended that the programmer be extra cautiouswhenmakingdirectuseofCcodeinsideATScode.Inpractice,myownexperienceclearlyindicatesthat the portion of C code inside my ATS code is highly likely to be the culprit for most ofencounteredbugs.

Thecodeemployedforillustrationinthischapterplussomeadditionalcodefortestingisavailableon-line.

Page 152: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ExternalGlobalNames

A function declared inATS can be given a global name of C-style so as to allow the function toappearinbothATScodeandCcode.Inparticular,thefunctioncanbeimplementedinATSandcalledinCorviceversa.

Inthefollowingcode,weseethattwofunctionsaredeclared:

extern

funfact(n:int):int

extern

funfact2(n:int,res:int):int="ext#fact2_in_c"

Thefirstfunction fact doesnothaveaglobalnamewhile thesecondfunction fact2 isassignedaglobalname fact2_in_c .Thesymbol ext# indicatesthat fact2_in_c istreatedasaglobalfunctioninCand its prototypeneeds tobedeclared (via the extern keyword) before it canbe called. If ext# iswritten in place of ext#fact2_in_c in the above declaration, then the global name for the functionfact2 inATSisassumedtobesameasthenameofthefunctioninATS.Inotherwords,writing ext#intheabovedeclarationisequivalenttowriting ext#fact2 .

Letusassumethat fact canbeimplementedasfollows:

implementfact(n)=fact2(n,1)

When compiling this implementation, the ATS compiler needs to form function names in thegeneratedC code to refer to fact and fact2 . For the former, the function name in theC code isdetermined by a set of rules (which take into account the issue of namespace). For the latter, thefunctionname is simplychosen tobe theassignedglobalname fact2_in_c .As is suggestedby thenameof fact2_in_c ,thisfunctioncanbedirectlyimplementedinCasfollows:

int

fact2_in_c(intn,intres)

{

while(n>0){res*=n;n-=1;};returnres;

}

Itisalsoallowedtoimplement fact2 inATSdirectlyasisshownbelow:

implement

fact2(n,res)=ifn>0thenfact2(n-1,n*res)elseres

Page 153: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Thisimplementationof fact2 canbecalledinCthroughthename fact2_in_c .

Ifboth fact2 and fact2_in_c areimplemented(theformerinATSandthelatterinC),thenalink-timeerroristobeissuedtoindicatethat fact2_in_c isimplementedrepeatedly.

Onecanalsodeclare fact2 asfollows:

extern

funfact2(n:int,res:int):int="mac#fact2_in_c"

Thesymbol mac# indicatesthat fact2_in_c istreatedlikeamacroinC.Inparticular, fact2_in_c canbe called without its prototype being declared first. As a matter of fact, it may not even have aprototype.Thisstyleofdeclarationnaturallyexpects fact2_in_c tobeimplementedinCdirectly.

Itisalsoallowedtouse sta# inplaceof mac# :

extern

funfact2(n:int,res:int):int="sta#fact2_in_c"

Ifdeclaredinthisstyle,whichonlyoccursrarelyinpractice, then fact2_in_c is treatedlikeastaticfunctioninC.

Forthesakeofcompleteness,Imentionasfollowsanotherwayofdeclaringastaticfunction:

staticfunfact2(n:int,res:int):int

Thisstyleofdeclarationisautomaticallytranslatedintothefollowingone:

externfunfact2(n:int,res:int):int="sta#"

wheretheuseof sta# meansthatthenamereferringto fact2 inCissimply fact2 .

Page 154: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ExternalTypesandValuesinATS

ExternaltypesandvaluescanbereadilyformedinATStorefertotypesandvaluesdeclaredinC.

SupposethatthereisatypeinCofthename some_type_in_c ,thenthistypecanbereferredtoinATSas $extype"some_type_in_c" . For instance, type definitions are introduced in the following code forsomeexternaltypesinC:

typedefCint=$extype"int"

typedefClint=$extype"longint"

typedefCllint=$extype"longlongint"

typedefCint2=$extype"struct{intx;inty;}"

SupposethatthereisavalueinCofthename some_value_in_c , thenthisvaluecanbereferredtoinATSas $extval( T ,"some_value_in_c") ,whereTisatypeinATSassignedtothisvalue.For instance,macrodefinitionsareintroducedinthefollowingcodeforsomeexternalvaluesinC:

macdefNULL=$extval(ptr,"0")

macdefstdin_ref=$extval(FILEref,"stdin")

macdefstdout_ref=$extval(FILEref,"stdout")

ExternalvaluescanalsobeformedtorefertofunctionsinCasdoneinthefollowingcode:

macdefatoi=$extval(string->int,"atoi")

macdefatol=$extval(string->lint,"atol")

macdefatof=$extval(string->double,"atof")

Note that there are other ways in ATS that are often more approriate for directly referring tofunctions inC.Typically, the primary purpose of forming an external value inATS is to allow aconstantdeclaredinCtobedirectlyreferredtoinATScode.

Page 155: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

InclusionofExternalCodeinATS

Just likeincludingassemblycodeinsideCcode, it isstraightforwardtoincludeCcodeinsideATScode.Forinstance,theexampleappearingatthebeginningofthischaptercanbewrittenasfollowsinasinglefile:

extern

funfact(n:int):int

extern

funfact2(n:int,res:int):int="ext#fact2_in_c"

implementfact(n)=fact2(n,1)

%{

int

fact2_in_c(intn,intres)

{

while(n>0){res*=n;n-=1;};returnres;

}

%}

ForC code to appear insideATS code, it needs to enclosed by the symbols %{ (opening) and %}(closing). Essentially, whatever code appearing between these two symbols is pasted into thegeneratedCcodeatanunspecifiedposition.IftheenclosedcodeisintendedtobeputatthebeginningofthegeneratedCcode,thenthesymbol %{^ shouldbeusedinplaceof %{ .If theenclosedcodeisintendedtobeputatthebottomofthegeneratedCcode,thenthesymbol %{$ shouldbeusedinplaceof %{ .

ItisalsoallowedtoputCcodebetweenthesymbols %{# and %} .Supposethat thereisafileofthenamefoo.satsthatcontainsCcodeincludedinthismanner.Iffoo.satsisstaloadedinanotherfile

of thenamefoo.dats, then the lines between %{# and %} infoo.sats are pasted into theC code

generatedfromcompilingfoo.dats.

Page 156: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

CallingExternalFunctionsinATS

It is straightforward tomake calls to external functions in ATS. For instance, the following codedemonstratesatypicalwaytodoso:

local

extern

fun__fprintf

:(FILEref,string(*fmt*),int,int)->int="mac#fprintf"

in(*inof[local]*)

//

valN=12

val_=__fprintf(stdout_ref,"fact(%i)=%i\n",N,fact(N))

//

end//endof[local]

wherethefunction fprintf (declaredinstdio.h)isgivena(local)name __fprintf andaninterface

appropriateforthecalltobemade.

There is also built-in support for calling external functions in ATS directly. For instance, thefollowingcodedoesessentiallythesameasthecodepresentedabove:

valN=12

val_=$extfcall(int,"fprintf",stdout_ref,"fact(%i)=%i\n",N,fact(N))

When $extfcall isemployedtomakeanexternalfunctioncall,itsfirstargumentisthereturntypeofthecall,anditssecondargumentisthenameofthecalledfunction(representedasastring),anditsrestofargumentsaretheargumentsofthecalledfunction.

Page 157: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

UnsafeC-styleProgramminginATS

ATS is probablynot a programming language easy for one towrite code in.WhileATSprovidesmany features to support safe (low-level) programming, it may take a long time and some greateffortsforaprogrammertolearnandthenmasterthesefeaturesbeforeheorshecanmakeeffectiveuse of them. In this section, I would like to present someATS codewritten in C-style thatmakestypicaluseofcertanunsafeprogrammingfeaturesinATS.ThisisaprogrammingstylethatshouldbefamiliartoanyprogrammerwhocanwriteCcodecompetently.

TherearealwaysoccasionswhereonemayfinditsensibletoprograminunsafeC-style.Sometimes,one just wants to get a running implementation and then relies on testing to detect and fix bugs.Sometimes, one simply does not know enough of ATS needed to implement a function in a safeprogramming manner. This list of occasions can be readily extended as one wishes. I myself dounsafeC-styleprogramminginATSfrequently,andIseeitasanecessaryskillforanyonewhonotjustonlywantstobeabletowritecodeinATSbutalsowantstodoithighlyproductively.LetusnowseeaconcreteexampleofunsafeC-styleprogramminginATS.

Suppose that we want to implement a function for comparing two given strings according to thestandardlexicographicordering.Letusnamethefunction strcmp andgiveitthefollowinginterface:

funstrcmp(str1:string,str2:string):int

Given two strings str1 and str2 , strcmp(str1, str2) is expected to return 1, -1, and 0 if str1 isgreater than, less than, and equal to str2 , respectively. An implementation of strcmp is given asfollows:

staload

UN="prelude/SATS/unsafe.sats"

(**************)

implement

strcmp(str1,str2)=let

//

funloop

(p1:ptr,p2:ptr):int=let

//

valc1=$UN.ptr0_get<uchar>(p1)

valc2=$UN.ptr0_get<uchar>(p2)

//

in

Page 158: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

case+0of

|_whenc1>c2=>1

|_whenc1<c2=>~1

|_(*c1=c2*)=>

(

if$UN.cast{int}(c1)=0

then0elseloop(ptr0_succ<uchar>(p1),ptr0_succ<uchar>(p2))

//endof[if]

)

end(*endof[loop]*)

//

in

loop(string2ptr(str1),string2ptr(str2))

end(*endof[strcmp]*)

ForaprogrammerfamilarwithC,theaboveimplementationof strcmp shouldbeeasilyaccessible.There are a variety of unsafe functions declared in unsafe.sats. Given a type T and a pointer p,ptr0_get<T> (p) fetches the value of the type T stored at the location towhich p points. Note thatptr0_get isinherentlyunsafeasthereissimplynoguaranteethatpactuallypointstoavalidmemorylocationwhereavalueof the typeT is stored.Thefunction cast ,which is also inherently unsafe,casts the type of a given value into any chosen type. The function template ptr0_succ , which isdeclared inpointer.sats, is type-safe.Given a typeT, ptr0_succ<T> (p) returns the pointer that is nbytesafterp,wherenequalsthesizeofT.

Pleasefindtheentirecodeforthisexampleon-line.

Forafunctionlike strcmp ,onecanreadilyimplementitinCdirectly.Forinstance,animplementationof strcmp inC,which isessentiallya translationof theabove implementationof strcmp inATS, isgivenasfollows:

intstrcmp(char*p1,char*p2)

{

intres;

unsignedcharc1,c2;

while(1)

{

c1=*p1;c2=*p2;

if(c1>c2){res=1;break;};

if(c1<c2){res=-1;break;};

if((int)c1==0){res=0;break;}else{p1++;p2++;};

}

returnres;

}

Page 159: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

However,writingATScode inC-stylecanoftenhaveadvantagesoverwritingCcodedirectly.Forinstance,thereisdirectsupportinATSbutnotinCforimplementingfunctiontemplates.InC,oneisessentiallyforced torelyonrather involveduseofmacros to implementfunction templates,whichmakes the code not only difficult to follow but also notoriously error-prone. Let us now see asfollowsafunctiontemplateimplementationinATSthatispartlytype-unsafe.

Supposewewantafunctionforcopyingintoagivenarraytheelementsstoredinalist.Letusnamethefunction array_copy_from_list andgiveitthefollowinginterface:

fun{a:t@ype}

array_copy_from_list(A:array0(a),xs:list0(a)):void

GivenatypeT, array0(T) isforanarray0-valuecontainingapointerpandasizensuchthatppointstoaC-stylearraystoringnelementsofthetypeT.

For the moment, let us require that the size of the array A equals the length of the list xs whenarray_copy_from_list(A,xs) iscalled.Followingisanimplementationof array_copy_from_list inATSthatmakesuseofanunsafefunction( ptr0_set )declaredinunsafe.sats:

staload

UN="prelude/SATS/unsafe.sats"

(**************)

implement

{a}(*tmp*)

array_copy_from_list

(A,xs)=let

//

funloop

(

p:ptr,xs:list0(a)

):void=

(

case+xsof

|list0_nil()=>()

|list0_cons(x,xs)=>let

val()=$UN.ptr0_set<a>(p,x)inloop(ptr0_succ<a>(p),xs)

end//endof[list0_cons]

)(*endof[loop]*)

//

in

Page 160: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

loop(array0_get_ref(A),xs)

end//endof[array_copy_from_list]

GivenatypeT,apointerp,andavaluexofthetypeT, ptr0_set<T>(p,x) storesthevaluexatthelocation to which p points. Like ptr0_get , ptr0_set is inherently unsafe as there is simply noguaranteethatpactuallypointstoavalidmemorylocationwhereavalueofthetypeTcanbestored.Thefunction array0_get_ref ,whichisdeclaredinarray0.sats,returnsthepointertotheC-stylearrayassociatedwithagivenarray0-value.

Pleasefindtheentirecodeforthisexampleon-line.

Page 161: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ExportingTypesinATSforUseinC

ThereisalsosupportinATSforexportingtypestomakethemavailableforuseinCdirectly.Inthefollowingexample,atypedefofthename int_and_string isexpectedtobedeclaredinthegeneratedCcodeforvaluesthatareassignedthetype (int,string) inATS:

extern

typedef

"int_and_string"=(int,string)

Essentially, int_and_string isdefinedinCasfollows:

typedef

struct{

intatslab__0;void*atslab__1;

}int_and_string;

Sometimes,wewanttoconstructinCvaluesofadatatypedeclaredinATS.Forinstance,letustrytoconstructavalueoftheform cons2(i,d) inCforanintegeriandadoubled,where cons2 isadataconstructorassociatedwiththefollowingdeclareddatatype abc :

datatypeabc=

|cons1ofint|cons2of(int,double)

Wheneveradataconstructorisdeclared,acorresponding(linear)typeconstructoriscreatedwhosenameequalstheconcatenationofthenameofthedataconstructorandthestring"_pstruct".Sointhecaseof the abovedeclareddatatype abc , the type constructors cons1_pstruct and cons2_pstruct arecreated,andthesetypeconstructorscanbeusedtoformtypesforboxedvaluesconstructedwiththedataconstructors cons1 and cons2 .

In the followingdeclaration, the type cons2_pstruct(int, double) inATS is exported toCunder thename cons2_node :

extern

vtypedef"cons2_node"=cons2_pstruct(int,double)

Implicitly, a typedef inCof the name cons2_node_ is also introduced for the unboxedportion of avalueconstructedwiththedataconstructor cons2 .Essentially,wehavethefollowinggeneratedcodeinC:

Page 162: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

typedef

struct{

intcontag;//constructortag

intatslab__0;doubleatslab__1;

}cons2_node_;

typedefcons2_node_*cons2_node;

Itisnowstraightforwardtocreateavalueoftheform cons2(i,d) inCdirectly:

cons2_node

cons2_make

(

inti,doubled

){

cons2_nodep;

p=ATS_MALLOC(sizeof(cons2_node_));

p->contag=1;

p->atslab__0=i;

p->atslab__1=d;

returnp;

}/*endof[cons2_make]*/

Notethatthetagsfor cons1 and cons2 are0and1,respectively,as cons1 and cons2 arethefirstandsecondconstructorsassociatedwiththedatatype abc .

Byassigninganinterfaceto cons2_make inATS,wecanreadilycheckwhether cons2_make behavesasexpected:

extern

funcons2_make(int,double):abc="mac#"

val-cons2(1,2.34)=cons2_make(1,2.34)

In general, it is essential for a pragrammer to acquire a solid understanding of low-level datarepresentation of a programming language in order to use that language in low-level systemsprogramming.Thelow-leveldatarepresentationofATScanbereadilyexplainedintermsoftypesinC,makingitstraightforward,whenneeded,toconstructandmanipulateATS-valuesinCdirectly.

Page 163: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:ConstructingaStaticallyAllocatedList

In embedded programming, static memory allocation is often preferred due to dynamic memoryallocationbeinglesspredictable.Ipresentasfollowsanexampleinwhichalist isconstructedwithstaticallyallocatedmemory.ThisexamplealsostronglyatteststoATSandCbeingintimatelyrelated.

Inordertostaticallyallocatememoryforlist-nodes,weneedtofirstformatypeforlist-nodessothatwecaninformtheCcompilerhowmuchmemoryisneededforeachlist-node.Inthefollowingcode,thetype list_node inATSisforboxedlist-nodes,andthistypeisexportedtoCunderthesamename:

//

vtypedef

list_node=list_cons_pstruct(int,ptr)//[list_node]forboxednodes

//

externvtypedef"list_node"=list_node//exporting[list_node]toC

//

Exporting list_node to C also introduces (implicitly) a typedef list_node_ in C for unboxed list-nodes.Sothefollowingtype list_node_ inATSispreciselywhatwewant(forunboxedlist-nodes):

typedeflist_node_=$extype"list_node_"//[list_node_]forunboxednodes

Thefollowingcodestaticallyallocatesanarrayoflist-nodesandtheninitializethesenodes,turningthearrayintoalist:

local

#defineN10

(*

**staticallocation

*)

varnodes=@[list_node_][N]()

funloop

(

p:ptr,i:int

):void=let

in

//

ifi<Nthenlet

valres=

$UN.castvwtp0{list_node}(p)

Page 164: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

val+list_cons(x,xs)=res

val(

)=x:=i*i

valp=ptr_succ<list_node_>(p)

vali=i+1

val()=(

ifi<Nthenxs:=pelsexs:=the_null_ptr

):void//endof[val]

val_(*ptr*)=$UN.castvwtp0{ptr}((view@x,view@xs|res))

in

loop(p,i)

endelse((*void*))//endof[if]

//

end//endof[loop]

in(*inof[local]*)

val()=loop(addr@nodes,0)

valxs_static=$UN.castvwtp0{list(int,N)}((view@nodes|addr@nodes))

val()=println!("xs_static=",xs_static)//0,1,4,9,16,...

end//endof[local]

The implementation of loop makes extensive use of unsafe C-style programming in ATS. ForsomeonefamiliarwithC,itshouldbestraightforwardtovisualizetheCcodethatcorrespondstothisimplementationdirectly.

Pleasefindtheentirecodeforthisexampleon-line.

Page 165: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

III.ProgrammingwithDependentTypesTableofContents9.IntroductiontoDependentTypes10.DatatypeRefinement11.Theorem-ProvinginATS/LF12.ProgrammingwithTheorem-Proving

Page 166: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 167: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 168: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter9.IntroductiontoDependentTypesThe types we have encountered so far in this book are often not adequately precise in capturingprogramminginvariants.Forinstance,ifweassignthetype int tobothofintegers0and1,thenwesimplycannotdistinguish0from1attheleveloftypes.Thismeansthat0and1areinterchangeableasfarastypecheckingisconcerned.Inotherwords,wecannotexpectaprogramerrortobecaughtduring typechecking if the error is caused by 0 beingmistyped as 1.This formof imprecision intypescanbecomeacripplinglimitationifweeverwanttobuildatype-basedspecificationlanguagethatisreasonablyexpressiveforpracticaluse.

Pleasefindon-line thecodeemployedfor illustrationinthischapterplussomeadditionalcodefortesting.

Page 169: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

EnhancedExpressivenessforSpecification

The primary purpose of introducing dependent types into the type system of ATS is to greatlyenhancetheexpressivenessoftypessothattheycanbeemployedtocaptureprograminvariantswithmuch greater precision. Generally speaking, dependent types are types dependent on values ofexpressions.Forinstance, bool isatypeconstructorinATSthatformsatype bool(b) whenappliedtoagivenbooleanvalueb.Asthistypecanonlybeassignedtoabooleanexpressionofthevalueb,itisoften referred to as a singleton type, that is, a type for exactly one value.Clearly, themeaning ofbool(b) dependsonthebooleanvalueb.Similarly, int isatypeconstructorinATSthatformsatypeint(i) whenappliedtoagivenintegeri.Thistypeisalsoasingletontypeasitcanonlybeassignedtoanintegerexpressionofthevaluei.Pleasenotethatboth bool and int areoverloadedastheyalsoreferto(non-dependent)types.Iwillgraduallyintroducemanyotherexamplesofdependenttypes.Inparticular,Iwillpresentaflexiblemeansfortheprogrammertodeclaredependentdatatypes.

ThestaticsofATSisasimply-typedlanguage,andthetypesinthislanguagearecalledsortssoastoavoidsomepotentialconfusion(with the typesfordynamic terms).Thefollowingfour listedsortsarecommonlyused:

bool:forstatictermsofbooleanvalues

int:forstatictermsofintegervalues

type:forstatictermsrepresentingboxedtypes(fordynamicterms)

t@ype:forstatictermsrepresentingunboxedtypes(fordynamicterms)

The sorts bool and int are classified as predicative sorts while the sorts type and t@ype areimpredicative.Aboxedtypeisastatictermofthesorttypewhileanunboxedtypeisastatictermofthesortt@ype.Astypes, bool and int [email protected], booland int arestatictermsofthesorts(bool->t@ype)and(int->t@ype),respectively.Alsonotethatthetypeconstructor list0 isofthesort(t@ype->type),which indicates that list0 formsaboxedtype when applied to an unboxed one. There are a variety of built-in static functions in ATS forconstructing static terms of the sorts bool and int, and I list as follows some of these functionstogetherwiththesortsassignedtothem:

~(negation):(int)->int

+(addition):(int,int)->int

Page 170: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

-(subtraction):(int,int)->int

*(multiplication):(int,int)->int

/(division):(int,int)->int

>(greater-than):(int,int)->bool

>=(greater-than-or-equal-to):(int,int)->bool

<(less-than):(int,int)->bool

<=(less-than-or-equal-to):(int,int)->bool

==(equal-to):(int,int)->bool

!=(not-equal-to):(int,int)->bool

<>(not-equal-to):(int,int)->bool

~(booleannegation):(bool)->bool

||(disjunction):(bool,bool)->bool

&&(conjunction):(bool,bool)->bool

By combining a sort with one or more predicates, we can define a subset sort. For instance, thefollowing subset sorts are defined in the filebasics_pre.sats,which is automatically loaded by theATScompiler:

sortdefnat={a:int|a>=0}//fornaturalnumbers

sortdefpos={a:int|a>=1}//forpositivenumbers

sortdefneg={a:int|a<=~1}//fornegativenumbers

sortdefnat1={a:nat|a<1}//for0

sortdefnat2={a:nat|a<2}//for0,1

sortdefnat3={a:nat|a<3}//for0,1,2

sortdefnat4={a:nat|a<4}//for0,1,2,3

Notethatpredicatescanbesequencedtogetherwiththesemicolonsymbol(;)toformaconjunction:

sortdefnat2={a:int|0<=a;a<2}//for0,1

sortdefnat3={a:int|0<=a;a<3}//for0,1,2

Page 171: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

sortdefsgn={i:int|~1<=i;i<=1}//for~1,0,1

Itisalsopossibletodefinethesubsetsortsnat2andnat3asfollows:

sortdefnat2={a:int|a==0||a==1}//for0,1

sortdefnat3={a:int|0<=a&&a<=2}//for0,1,2

where || and && standsfordisjunctionandconjunction,respectively.

In order to unleash the expressiveness of dependent types, we need to employ both universal andexistentialquantificationoverstaticvariables.Forinstance,thetype Int inATSisdefinedasfollows:

typedefInt=[a:int]int(a)//forunspecifiedintegers

where the syntax [a:int] means existential quantification over a static variable a of the sort int.Essentially,thismeansthatforeachvalueofthetype Int ,thereexistsanintegerIsuchthatthevalueisofthetype int(I) .Therefore,anyvaluethatcanbegiventhetype int canalsobegiventhetypeInt .Atypelike Int isoftenreferredtoasanexistentiallyquantifiedtype.Asanotherexample, thetype Nat inATSisdefinedasfollows:

typedefNat=[a:int|a>=0]int(a)//fornaturalnumbers

wherethesyntax [a:int|a>=0] meansexistentialquantificationoverastaticvariable a ofthesortintthatsatisfiestheconstraint a>=0 .Therefore,eachvalueofthetype Nat canbeassignedthetypeint(I) forsomeintegerIsatisfyingI>=0.Giventhat int(I) isasingletontype,thevalueequalsIandisthusanaturalnumber.Thismeansthatthetype Nat isfornaturalnumbers.ThedefinitionofNat canalsobegivenasfollows:

typedefNat=[a:nat]int(a)//fornaturalnumbers

wherethesyntax [a:nat] isjustaformofsyntacticsugarthatautomaticallyexpandsinto [a:int|a>=0] .

Atthispoint,typeshavealreadybecomemuchmoreexpressive.Forinstance,wecouldonlyassignthe type (int) -> int to a function that maps integers to natural numbers (e.g., the function thatcomputes the absolutevalueof agiven integer), butwecannowdobetterby assigning it the type(Int)->Nat ,whichisclearlymoreprecise.Inordertorelateattheleveloftypesthereturnvalueofafunctiontoitsarguments,weneeduniversalquantification.Forinstance,thefollowinguniversallyquantifiedtypeisforafunctionthatreturnsthesuccessorofitsintegerargument:

Page 172: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

{i:int}int(i)->int(i+1)

wherethesyntax {i:int} meansuniversalquantificationoverastaticvariable i ofthesort int andthescopeofthisquantificationisthefunctiontypefollowingit.Onemaythinkthatthisfunctiontypeisalsoasingletontypeastheonlyfunctionofthistypeisthesuccessorfunctiononintegers.Actually,thereareinfinitelymaypartialfunctionsthatcanbegiventhistypeaswell.Forthesuccessorfunctiononnaturalnumbers,wecanusethefollowingtype:

{i:int|i>=0}int(i)->int(i+1)

wherethesyntax {i:int|i>=0} meansuniversalquantificationoverastaticvariable i ofthesortintthatsatisfiestheconstraint i>=0 .Thistypecanalsobewrittenasfollows:

{i:nat}int(i)->int(i+1)

wherethesyntax {i:nat} automaticallyexpandsinto {i:int|i>=0} .Ilistasfollowstheinterfacesforsomecommonlyusedfunctionsonintegers:

fung1int_neg{i:int}(inti):int(~i)//negation

fung1int_add{i,j:int}(inti,intj):int(i+j)//addition

fung1int_sub{i,j:int}(inti,intj):int(i-j)//subtraction

fung1int_mul{i,j:int}(inti,intj):int(i*j)//multiplication

fung1int_div{i,j:int}(inti,intj):int(i/j)//division

fung1int_lt{i,j:int}(inti,intj):bool(i<j)//less-than

fung1int_lte{i,j:int}(inti,intj):bool(i<=j)//less-than-or-equal-to

fung1int_gt{i,j:int}(inti,intj):bool(i>j)//greater-than

fung1int_gte{i,j:int}(inti,intj):bool(i>=j)//greater-than-or-equal-to

fung1int_eq{i,j:int}(inti,intj):bool(i==j)//equal-to

fung1int_neq{i,j:int}(inti,intj):bool(i!=j)//not-equal-to

These interfaces are all declared in the file integer.sats,which is automatically loadedby theATScompiler. Note that the functions listed here can all be referred to by their standard names: ~ forg1int_neg,+forg1int_add,-forg1int_sub,*forg1int_mul, / forg1int_div,<forg1int_lt,<=forg1int_lte,>forg1int_gt,>=forg1int_gte,=forg1int_eq,!=forg1int_neq,<>forg1int_neq(mostofthetime).

It isnowapropermoment forme to raise an interestingquestion:Whatdoes adependently typedinterfaceforthefactorialfunctionlooklike?Afterseeingtheaboveexamples,itisonlynaturalforonetoexpectsomethingalongthefollowinglineofthought:

Page 173: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

fung1int_fact{i:nat}(i:inti):int(fact(i))

wherefact isastaticversionof thefactorialfunction.Theveryproblemwiththissolutionis thatastaticfunctionlikefactcannotbedefinedinATS.ThestaticsofATSisasimply-typedlanguagethatdoesnotallowanyrecursivemeanstobeemployedintheconstructionofstaticterms.Thisdesignisadopted primarily to ensure that the equality on static terms can be decided based on a practicalalgorithm.Astypecheckinginvolvingdependenttypesessentiallyturnsintoverifyingwhetherasetofequalities(andsomebuilt-inpredicates)onstatictermshold,suchadesignisofvitalimportancetothegoalofsupportingpracticalprogrammingwithdependenttypes.Inordertoassignaninterfacetothe factorial function that precisely matches the definition of the function, we need to employ amechanisminATSforcombiningprogrammingwiththeorem-proving.This isa topicIwillcoverlater.

Page 174: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Constraint-SolvingduringTypechecking

Typechecking inATS involves generating and solving constraints.As an example, the code belowimplementsthewell-knownfactorialfunction:

fun

fact{n:nat}

(x:intn):[r:nat]intr=ifx>0thenx*fact(x-1)else1

//endof[fact]

Inthisimplementation,thefunction fact isassignedthefollowingtype:

{n:nat}int(n)->[r:nat]int(r)

whichmeansthat fact returnsanaturalnumberrwhenappliedtoanaturalnumbern.Whenthecodeistypechecked,thefollowingconstraintsneedtobesolved:

Foreachnaturalnumbern,n>0impliesn-1>=0

Foreachnaturalnumbernandeachnaturalnumberr1,n>0impliesn*r1>=0

Foreachnaturalnumbern,1>=0holds.

The first constraint is generated due to the call fact(x-1) , which requires that x-1 be a naturalnumber.Thesecondconstraintisgeneratedinordertoverifythat x*fact(x-1) isanaturalnumberundertheassumptionthat fact(x-1) isanaturalnumber.Thethirdconstraintisgeneratedinordertoverify that 1 is a natural number. The first and the third constraints can be readily solved by theconstraint solver in ATS, which is based on the Fourier-Motzkin variable elimination method.However, the second constraint cannot be handled by the constraint solver as it is nonlinear: Theconstraintcannotbeturnedintoalinearintegerprogrammingproblemduetotheoccurrenceofthenonlinearterm(n*r1).WhilenonlinearconstraintscannotbehandledautomaticallybytheconstraintsolverinATS,theprogrammercanverifythembyconstructingproofsinATSexplicitly.Iwillcovertheissueofexplicitproofconstructioninanelaboratedmannerelsewhere.

Bydefault,theconstraint-solverimplementedforATS/Postiatsmakesuseofthestandardarithmeticofinfiniteprecision.Forthesakeofefficiency,onemayalsochoosetousemachine-levelarithmeticfor solving integer constraints. Due to potential arithmetic overflow, results returned by theconstraint-solverthatusesmachine-levelarithmeticcanbeincorrect(butIhavesofarnotknowinglyencounteredsuchasituationinpractice).

Page 175: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 176: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:StringProcessing

AstringinATSisrepresentedinthesamemannerasinC:Itisasequenceofadjacentlystorednon-nullcharactersfollowedbythenullcharacter,anditslengthisthenumberofnon-nullcharactersinthe sequence. Conventionally, such strings are often referred to as C-style strings, which arenotoriouslydifficulttobeprocessedsafely(asisclearlyindicatedbysomanybugsandbreachesduetomisusingsuchstrings).Asamatteroffact,ATSisthefirstpracticalprogramminglanguagethatIknowcanfullysupportsafeprocessingofC-stylestrings.InATS, string isatypeconstructorofthesort(int) -> type. Given a static integer n, string(n) is the type for strings of length n.Note thatstring also refers to a non-dependent type for strings of unspecified length, which is basicallyequivalenttothetype String definedasfollows:

typedefString=[n:nat]string(n)

Thefollowingtwofunctionsarecommonlyusedfortraversingagivenstring:

funstring_is_atend

{n:int}{i:nat|i<=n}

(str:string(n),i:size_t(i)):bool(i==n)

//endof[string_is_atend]

funstring_isnot_atend

{n:int}{i:nat|i<=n}

(str:string(n),i:size_t(i)):bool(i<n)

//endof[string_isnot_atend]

Obviously,eitheroneofthemcanbeimplementedbasedontheother.Asanexample,thefollowingcodeimplementsafunctionthatcomputesthelengthofagivenstring:

fun

string_length

{n:nat}(

str:string(n)

):size_t(n)=let

funloop{i:nat|i<=n}.<n-i>.

(str:stringn,i:size_ti):size_t(n)=

ifstring_isnot_atend(str,i)thenloop(str,succ(i))elsei

//endof[loop]

in

loop(str,i2sz(0))

end//endof[string_length]

Page 177: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Notethatthefunction loop inthebodyof string_length isdefinedtail-recursively,whichcanthenbetranslatedintoagenuineloopinthegeneratedCcode.Althoughthisimplementationof string_lengthlooks fairly plain right now, it was actually an exciting achievement in the pursuit of practicalprogrammingwithdependenttypes.

Thefollowingtwofunctionsareforaccessingandupdatingcharactersstoredinstrings:

typedefcharNZ=[c:int|c!='\000']char(c)

fun

string_get_at{n:int}

{i:nat|i<n}(str:stringn,i:size_ti):charNZ

overload[]withstring_get_at

fun

string_set_char_at{n:int}

{i:nat|i<n}(str:stringn,i:size_ti,c:charNZ):void

overload[]withstring_set_char_at

Thetypeconstructor char isofthesort(char)->t@ype,whichtakesastaticcharacterc toformasingleton type char(c) for the only character equal to c. Thus, the type charNZ is for all non-nullcharacters.Thefollowingdefinedfunction string_find traversesastringfromlefttorighttocheckwhetheragivencharacteroccursinthestring:

//

typedef

sizeLt(n:int)=[i:nat|i<n]size_t(i)

//

fun

string_find{n:nat}

(

str:stringn,c0:char

):Option(sizeLtn)=let

typedefres=sizeLt(n)

funloop{i:nat|i<=n}

(

str:stringn,c0:char,i:size_ti

):Option(res)=let

valisnot=string_isnot_atend(str,i)

in

ifisnotthen

if(c0=str[i])thenSome{res}(i)elseloop(str,c0,succ(i))

elseNone()//endof[if]

end(*endof[loop]*)

Page 178: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

in

loop(str,c0,i2sz(0))

end//endof[string_find]

//

If the character c0 occurs in the string str , then a value of the form Some(i) is returned,when ireferstothepositionofthefirstoccurrenceof c0 (countingfromlefttoright).Otherwise,thevalueNone() isreturned.

Thereissomeinherentinefficiencyintheimplementationof string_find :Agivenposition i isfirstcheckedtoseeifitisstrictlylessthanthelengthofthestring str bycalling string_isnot_atend ,and,ifitis,thecharacterstoredatthepositioninthestringisfetchedbycalling string_get_at .Thesetwofunctioncallsaremergedintooneinthefollowingimplementation:

//

//Thisimplementationdoesthesameas[string_find]

//butshouldbemoreefficient.

//

fun

string_find2{n:nat}

(

str:stringn,c0:char

):Option(sizeLtn)=let

//

fun

loop{i:nat|i<=n}

(

str:stringn

,c0:char,i:size_ti

):Option(sizeLtn)=let

typedefres=sizeLt(n)

valc=string_test_at(str,i)

in

ifc!='\000'then

(

if(c0=c)thenSome{res}(i)elseloop(str,c0,succ(i))

)elseNone((*void*))//endof[if]

end//endof[loop]

//

in

loop(str,c0,i2sz(0))

end//endof[string_find2]

Theinterfaceforthefunction string_test_at isgivenasfollows:

Page 179: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

fun

string_test_at

{n:int}{i:nat|i<=n}

(

str:string(n),i:size_t(i)

):[c:char|(c!=NUL&&i<n)||(c==NUL&&i>=n)]charc

//endof[string_test_at]

Bycheckingthereturnvalueofacallto string_test_at ,wecanreadilytellwhethertheposition i isattheendofthestring str .

Handlingstringssafelyandefficientlyisacomplicatedmatterinprogramminglanguagedesign,andagreatdealofinformationaboutaprogramminglanguagecanoftenberevealedbysimplystudyingitstreatmentofstrings.InATS,properlyprocessingC-stylestringsalsomakesessentialuseoflineartypes,whichIwillcoverinanotherpartofthisbook.

Page 180: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:BinarySearchonArrays

GivenatypeTofthesortt@ypeandastaticintegerI(i.e.,astatictermofthesortint), arrayref(T,I)isaboxedtypeforarraysofsizeIinwhicheachstoredelementisofthetypeT.Notethatsucharrayshave no size information attached to them. The following interface is for a function templatearray_make_elt thatcanbecalledtocreateanarray(withnosizeinformationattachedtoit):

fun{a:t@ype}

array_make_elt{n:int}(asz:size_tn,elt:a):arrayref(a,n)

GivenastaticintegerI,thetype size_t(I) isasingletontypeforavalueofthetypesize_tinCthatrepresentstheintegerequaltoI.Thefunctiontemplatesforreadingfromandwritingtoanarraycellhavethefollowinginterfaces:

fun{a:t@ype}

arrayref_get_at

{n:int}{i:nat|i<n}(A:arrayref(a,n),i:size_ti):a

overload[]witharrayref_get_at

fun{a:t@ype}

arrayref_set_at

{n:int}{i:nat|i<n}(A:arrayref(a,n),i:size_ti,x:a):void

overload[]witharrayref_set_at

Note that these twofunction templatesdonot incuranyrun-timearray-boundschecking:The typesassignedtothemguaranteethateachindexusedforarraysubscriptingisalwayslegal,thatis,withintheboundsofthearraybeingsubscripted.

As a convincing example of practical programming with dependent types, the following codeimplementsthestandardbinarysearchalgorithmonanorderedarray:

fun{

a:t@ype

}bsearch_arr{n:nat}

(

A:arrayref(a,n),n:intn,x0:a,cmp:(a,a)->int

):int=let

//

funloop

{i,j:int|

0<=i;i<=j+1;j+1<=n}

(

Page 181: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

A:arrayref(a,n),l:inti,u:intj

):<cloref1>int=

(

ifl<=uthenlet

valm=l+half(u-l)

valx=A[m]

valsgn=cmp(x0,x)

in

ifsgn>=0thenloop(A,m+1,u)elseloop(A,l,m-1)

endelseu//endof[if]

)(*endof[loop]*)

//

in

loop(A,0,n-1)

end//endof[bsearch_arr]

Thefunction loop definedinthebodyof bsearch_arr searchesthesegmentofthearray A betweentheindices l and u ,inclusive.Clearly,thetypeassignedto loop indicatesthattheintegervaluesiandjofthearguments l and u mustsatisfythepreconditionconsistingoftheconstraints0<=i,i<=j+1,and j+1 <= n, where n is the size of the array being searched. The progress we have made byintroducing dependent types intoATS should be evident in this example:We can not only specifymuchmorepreciselythanbeforebutalsoenforceeffectivelytheenhancedprecisioninspecification.

Pleasefindon-line thecodeemployedfor illustration in thissectionplussomeadditionalcodefortesting.

Page 182: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Termination-CheckingforRecursiveFunctions

ThereisamechanisminATSthatallowstheprogrammertosupplyterminationmetricsforcheckingwhetherrecursivelydefinedfunctionsareterminating.Itwillsoonbecomeclearthatthismechanismof termination-checking plays a fundamental role in the design of ATS/LF, a theorem-provingsubsystemofATS,whereproofsareconstructedastotalfunctionalprograms.

A terminationmetric is justa tupleofnaturalnumbersand thestandard lexicographicorderingonnatural numbers is used to order such tuples. In the following example, a singleton metric n issuppliedtoverifythattherecursivefunction fact isterminating,where n isthevalueoftheintegerargumentof fact :

funfact{n:nat}.<n>.

(x:intn):int=ifx>0thenx*fact(x-1)else1

//endof[fact]

Notethatthemetricattachedtotherecursivecall fact(x-1) is n-1 ,whichisstrictlylessthantheinitialmetric n .Essentially,termination-checkinginATSverifiesthatthemetricattachedtoeachrecursivecallinthebodyofafunctionisstrictlylessthattheinitialmetricattachedtothefunction.

Amoredifficultandalsomoreinterestingexampleisgivenasfollows,wheretheMacCarthy's91-functionisimplemented:

funf91{i:int}.<max(101-i,0)>.(x:inti)

:[j:int|(i<101&&j==91)||(i>=101&&j==i-10)]int(j)=

ifx>=101thenx-10elsef91(f91(x+11))

//endof[f91]

Themetric supplied to verify the termination of f91 is max(101-i,0) , where i is the value of theinteger argument of f91 . Please try to verify manually that this metric suffices for verifying theterminationof f91 .

Asanotherexample,thefollowingcodeimplementstheAckermann'sfunction,whichiswell-knownforbeingrecursivebutnotprimitiverecursive:

funacker

{m,n:nat}.<m,n>.

(x:intm,y:intn):Nat=

ifx>0then

ify>0thenacker(x-1,acker(x,y-1))elseacker(x-1,1)

Page 183: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

elsey+1

//endof[acker]

Themetricsuppliedforverifyingtheterminationof acker isapair (m,n) ,where m and n arevaluesofthetwointegerargumentsof acker .Themetricsattachedtothethreerecursivecallsto acker are,fromleft toright, (m-1,k) forsomenaturalnumberk, (m,n-1) ,and (m-1,1) .Clearly, thesemetricsareallstrictlylessthantheinitialmetric (m,n) accordingtothelexicographicorderingonpairsofnaturalnumbers.

Termination-checking formutually recursive functions is similar. In the following example, isevnand isodd aredefinedmutuallyrecursively:

funisevn

{n:nat}.<2*n>.

(n:intn):bool=

ifn=0thentrueelseisodd(n-1)

andisodd

{n:nat}.<2*n+1>.

(n:intn):bool=not(isevn(n))

The metrics supplied for verifying the termination of isevn and isodd are 2*n and 2*n+1 ,respectively,where n isthevalueoftheintegerargumentof isevn andalsothevalueoftheintegerargument of isodd . Clearly, if the metrics (n, 0) and (n, 1) are supplied for isevn and isodd ,respectively,theterminationofthesetwofunctionscanalsobeverified.Notethat it isrequiredthatthemetricsformutuallyrecursivelydefinedfunctionsbetuplesofthesamelength.

Page 184: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:DependentTypesforDebugging

Givenanintegerx>=0,theintegersquarerootofxisthegreatestintegerisatisfyingi*i<=x.Animplementationoftheintegersquarerootfunctionisgivenasfollowsbasedonthemethodofbinarysearch:

fun

isqrt

(

x:int

):int=let

//

fun

search

(

x:int,l:int,r:int

):int=let

valdiff=r-l

in

case+0of

|_whendiff>0=>let

valm=l+(diff/2)

in

//x<m*mcanoverfloweasily

ifx/m<m

thensearch(x,l,m)elsesearch(x,m,r)

//endof[if]

end//endof[if]

|_(*diff<=0*)=>l(*theresultisfound*)

end//endof[search]

//

in

search(x,0,x)

end//endof[isqrt]

Thisimplementationpassestypechecking,butitseemstobeloopingforeverwhentested.Insteadofgoingintothestandardroutineofdebugging(e.g.,byinsertingcallstosomeprintingfunctions),letusattempttoidentifythecauseforinfiniteloopingbyprovingtheterminationofthefunction searchthrough theuseofdependent types.Clearly, thefunction search isassigned the function type (int,int,int)->int ,meaningthat search takesthreeintegersasitsargumentsandreturnsanintegerasitsresult,andthereisnotmuchelsethatcanbegatheredfromanon-dependenttypeassuch.However,theprogrammermayhavethoughtthatthefunction search shouldpossessthefollowinginvariants(ifimplementedcorrectly):

Page 185: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

l*l<=xandx<=r*rmustholdwhen search(x,l,r) iscalled.

Assumel*l<=x<r*rforsomeintegersx,l,r.Ifarecursivecall search(x,l1,r1) forsomeintegersl1andr1isencounteredinthebodyof search(x,l,r) ,thenr1-l1<r-lmusthold.Thisinvariantimpliesthat search isterminating.

ThoughthefirstinvariantcanbecapturedinthetypesystemofATS,itissomewhatinvolvedtodosoduetotheneedforhandlingnonlinearconstraints.Instead,letustrytoassign search the followingdependentfunctiontype:

{x:nat}{l,r:nat|l<r}.<r-l>.(int(x),int(l),int(r))->int

whichcaptures aweaker invariant stating that l< rmustholdwhen search(x, l, r) is called.Theterminationmetric .<r-l>. isprovidedforcheckingthatthefunction search isterminating.Whenweassign search thedependentfunctiontype,wehavetomodifyitsbodyascertainerrorsareotherwisereported during typechecking. The following code we obtain after propermodification does passtypechecking:

fun

isqrt

{x:nat}

(

x:intx

):int=let

//

fun

search

{x,l,r:nat|l<r}.<r-l>.

(

x:intx,l:intl,r:intr

):int=let

valdiff=r-l

in

case+0of

|_whendiff>1=>let

valm=l+half(diff)

in

ifx/m<m

thensearch(x,l,m)elsesearch(x,m,r)

//endof[if]

end//endof[if]

|_(*diff<=1*)=>l(*theresultisfound*)

end//endof[search]

Page 186: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

//

in

ifx>0thensearch(x,0,x)else0

end//endof[isqrt]

It isnowratherclear that infinite looping in theprevious implementationof search mayhappen ifsearch(x,l,r) iscalledinasitualtionwhere r-l equals1asthiscallcanpotentiallyleadtoanothercall to search of the same arguments. However, such a call leads to a type-error after search isassignedtheaforementioneddependentfunctiontype.

Bybeingpreciseandbeingabletoenforceprecisioneffectively,theprogrammerwillsurelynoticethathisorherneedforrun-timedebuggingisdiminishingrapidly.

Page 187: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 188: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 189: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter10.DatatypeRefinementThedatatypemechanisminATSisadoptedfromMLdirectly,andit isreallyasignatoryfeatureinfunctional programming. However, the datatypes we have seen so far are not very precise whenemployedtoclassifyvalues.Forinstance,givenatypeT,thetype list0(T) isforvaluesrepresentingbothemptyandnon-emptylistsconsistingofelementsofthetypeT.Therefore,emptyandnon-emptylistscannotbedistinguishedattheleveloftypes.Thislimitationseverelydiminishestheeffectivenessof datatypes of ML-style in capturing program invariants. In ATS, datatypes of ML-style can berefined into dependent datatypes of DML-style, where DML refers to the programming languageDependentML,theimmediateprecursorofATS.Withsuchrefinement,datatypescanclassifyvalueswithgreatlyenhancedprecision.

Thecodeemployedforillustrationinthischapterplussomeadditionalcodefortestingisavailableon-line.

Page 190: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

DependentDatatypes

The syntax for declaring dependent datatypes is mostly similar to the syntax for declaring non-dependentdatatypes:Forinstance,thedependentdatatype list inATSisdeclaredasfollows:

datatypelist(t@ype+,int)=

|{a:t@ype}list_nil(a,0)of()//[of()]isoptional

|{a:t@ype}{n:nat}list_cons(a,n+1)of(a,list(a,n))

Moreprecisely, list isdeclaredasatypeconstructorofthesort(t@ype,int)->type,whichmeansthat list takes an unboxed type and a static integer to form a boxed type. The keyword t@ype+

indicates that list is covariant at its first parameter (of the sort t@ype), that is, list(T1, I) isconsideredasubtypeof list(T2,I) ifT1isasubtypeofT2.Thereisalsothekeyword t@ype- forindicating the declared type constructor being contravariant at a parameter, but it is rarely used inpractice.Also,keywordslike type+ and type- areinterpretedsimilarly.

There two data (or value) constructors list_nil and list_cons associated with list , which aredeclaredtobeofthefollowingtypes:

list_nil:{a:t@ype}()->list(a,0)

list_cons:{a:t@ype}{n:nat}(a,list(a,n))->list(a,n+1)

GivenatypeTandastaticintegerI,thetype list(T,I) isforvaluesrepresentinglistsoflengthIinwhicheachelementisofthetypeT.Hence,thetypesof list_nil and list_cons mean that list_nilformsalistoflength0and list_cons formsalistoflengthn+1ifappliedtoanelementandalistoflengthn.Notethatitisalsopossibletodeclare list asfollowsinamoreconcisestyle:

datatypelist(a:t@ype+,int)=

|list_nil(a,0)of()//[of()]isoptional

|{n:nat}list_cons(a,n+1)of(a,list(a,n))

Theuseof a:t@ype+ (insteadof t@ype+ ) introduces implicitlyauniversalquantifierover a for thetypeassignedtoeachdataconstructorassociatedwiththedeclaredtypeconstructor list .

Asanexampleofprogrammingwithdependentdatatypes,thefollowingcodeimplementsafunctiontemplateforcomputingthelengthofagivenlist:

fun{

a:t@ype

}list_length

Page 191: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

{n:nat}.<n>.

//.<n>.isaterminationmetric

(xs:list(a,n)):int(n)=case+xsof

|list_nil()=>0

|list_cons(_,xs1)=>1+list_length(xs1)

//endof[list_length]

Thetypeassignedtothefunction list_length indicatesthatthefunctiontakesalistoflengthnforanynatural number n and returns an integer of value n. In addition, the function is verified to beterminating.Therefore, list_length isguaranteedtoimplementthefunctionthatcomputesthelengthof a given list. I now briefly explain how typechecking can be performed on the definition oflist_length .Letusfirstseethatthethefollowingclausetypechecks:

|list_cons(_,xs1)=>1+list_length(xs1)

Whatweneedtoverifyisthattheexpressionontherighthandsideofthesymbol => canbeassignedthetype int(n) undertheassumptionthat xs matchesthepatternonthelefthandsideofthesymbol=> . Let us assume that xs1 is of the type list(a, n1) for some natural number n1 , and thisassumptionimpliesthatthepattern list_cons(_,xs1) isofthetype list(a, n1+1) .Clearly,matchingxs against the pattern list_cons(_, xs1) generates a condition n=n1+1 . It is also clear thatlist_length(xs1) isofthetype int(n1) andthus 1+list_length(xs1) isofthetype int(1+n1) .Asthecondition n=n1+1 implies n=1+n1 , 1 + list_length(xs1) canbegiven the type int(n) . So this clausetypechecks.Notethatmatching xs againstthepattern list_nil() generatestheassumption n=0 ,whichimpliesthat 0 isofthetype int(n) .Therefore,thefollowingclausetypechecks:

|list_nil()=>0

Giventhatthetwoclausestypecheckproperly,thecase-expressioncontainingthemcanbeassignedthetype int(n) .Therefore,thedefinitionof list_length typechecks.

As the recursive call in the body of the above defined function list_length is not a tail-call, thefunction may not be able to handle a long list (e.g., one that contains 1 million elements). Thefollowingcodegivesanotherimplementationforcomputingthelengthofagivenlist:

fun{

a:t@ype

}list_length{n:nat}.<>.

(xs:list(a,n)):int(n)=let

//loop:{i,j:nat}(list(a,i),int(j))->int(i+j)

funloop{i,j:nat}.<i>.

Page 192: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

//.<i>.isaterminationmetric

(xs:list(a,i),j:intj):int(i+j)=case+xsof

|list_cons(_,xs1)=>loop(xs1,j+1)|list_nil()=>j

//endof[loop]

in

loop(xs,0)

end//endof[list_length]

This time, list_length is based on a tail-recursive function loop and thus can handle lists of anylength inconstantstackspace.Note that the typeassignedto loop indicates that loop takesa listoflengthiandanintegerofvaluejforsomenaturalnumbersiandjandreturnsanintegerofvaluei+j.Also, loop isverifiedtobeterminating.

Thereisalsoadependentdatatype option inATSforformingoptionalvalues:

datatype

option(a:t@ype+,bool)=

|Some(a,true)ofa|None(a,false)of()

//endof[option]

Asanexample,thefollowingfunctiontemplate list_last triestofindthelastelementinagivenlist:

fun{

a:t@ype

}list_last

{n:nat}.<>.

(

xs:list(a,n)

):option(a,n>0)=let

//

funloop

{n:pos}.<n>.

(

xs:list(a,n)

):a=let

val+list_cons(_,xs1)=xs

in

case+xs1of

|list_cons_=>loop(xs1)

|list_nil()=>let

val+list_cons(x,_)=xsinx

end//endof[list_nil]

end//endof[loop]

//

in

Page 193: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

case+xsof

|list_cons_=>Some(loop(xs))|list_nil()=>None()

end//endof[list_last]

Theinnerfunction loop isevidentlytail-recursiveanditisverifiedtobeterminating.

Afteraprogrammerbecomesfamilarwith list and option ,thereislittleincentiveforhimorhertouse list0 and option0 anymore. Internally, values of list and list0 have exactly the samerepresentation and there are cast functions of zero run-time cost in ATS for translating betweenvaluesof list and list0 .Thesameappliestovaluesof option and option0 aswell.

Page 194: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:FunctionTemplatesonLists(Redux)

I have presented previously implementation of some commonly used function templates on listsformed with the constructors list0_nil and list0_cons . This time, I present as followsimplementation of the corresponding function templates on lists formed with the constructorslist_nil and list_cons ,whichmakeitpossibletoassignmoreaccuratetypestothesetemplates.

Pleasefindtheentirecodeinthissectionplussomeadditionalcodefortestingon-line.

Appending: list_append

Giventwolistsxsandysofthetypes list(T,I1) and list(T,I2) forsometypeTandintegersI1andI2, list_append(xs,ys) returnsalistofthetype list(T,I1+I2) thatistheconcatenationofxsandys:

fun{

a:t@ype

}list_append

{m,n:nat}.<m>.

(

xs:list(a,m),ys:list(a,n)

):list(a,m+n)=case+xsof

|list_nil()=>ys

|list_cons(x,xs)=>list_cons(x,list_append(xs,ys))

//endof[list_append]

Clearly,thisimplementationof list_append isnottail-recursive.

ReverseAppending: list_reverse_append

Giventwolistsxsandysofthetype list(T,I1) and list(T,I2) forsometypeTandintegersI1andI2, list_reverse_append(xs,ys) returnsalistofthetype list(T,I1+I2) thatistheconcatenationofthereverseofxsandys:

fun{

a:t@ype

}list_reverse_append

{m,n:nat}.<m>.

(

xs:list(a,m),ys:list(a,n)

):list(a,m+n)=case+xsof

Page 195: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

|list_nil()=>ys

|list_cons(x,xs)=>

list_reverse_append(xs,list_cons(x,ys))

//endof[list_reverse_append]

Clearly,thisimplementationof list_reverse_append istail-recursive.

Reversing: list_reverse

Givenalistxs, list_reverse(xs) returnsthereverseofxs,whichisofthesamelengthasxs:

fun{a:t@ype}

list_reverse{n:nat}.<>.//definednon-recursively

(xs:list(a,n)):list(a,n)=list_reverse_append(xs,list_nil)

//endof[list_reverse]

Mapping: list_map

Givenalistxsofthetype list(T1,I) forsometypeT1andintegerIandaclosurefunctionfofthetype T1-<cloref1>T2 forsomeT2, list_map(xs) returnsalistysofthetype list(T2,I)) :

fun{

a:t@ype}

{b:t@ype

}list_map

{n:nat}.<n>.

(

xs:list(a,n),f:a-<cloref1>b

):list(b,n)=case+xsof

|list_nil()=>list_nil()

|list_cons(x,xs)=>list_cons(fx,list_map(xs,f))

//endof[list_map]

Each element y in ys equals f(x), where x is the corresponding element in xs. Clearly, thisimplementationof list_map isnottail-recursive.

Zipping: list_zip

Given two listsxs andysof the types list(T1, I) and list(T2, I) for some typesT1 andT2 and

Page 196: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

integerI,respectively, list_zip(xs,ys) returnsalistzsofthetype list((T1,T2),I) .

fun{

a,b:t@ype

}list_zip

{n:nat}.<n>.

(

xs:list(a,n),ys:list(b,n)

):list((a,b),n)=

(

case+(xs,ys)of

|(list_cons(x,xs),

list_cons(y,ys))=>

list_cons((x,y),list_zip(xs,ys))

|(list_nil(),list_nil())=>list_nil()

)(*endof[list_zip]*)

Eachelementzinzsequalsthepair(x,y),wherexandyarethecorrespondingelementsinxsandys,respectively.Clearly,thisimplementationof list_zip isnottail-recursive.

Zippingwith: list_zipwith

Given two listsxs andysof the types list(T1, I) and list(T2, I) for some typesT1 andT2 andintegerI,respectively,andaclosurefunctionfofthetype (T1,T2)-<cloref1>T3 forsometypeT3,list_zipwith(xs,ys,f) returnsalistzsofthetype list(T3,I) :

fun{

a,b:t@ype

}{c:t@ype

}list_zipwith

{n:nat}.<n>.

(

xs:list(a,n)

,ys:list(b,n)

,f:(a,b)-<cloref1>c

):list(c,n)=case+(xs,ys)of

|(list_cons(x,xs),

list_cons(y,ys))=>

list_cons(f(x,y),list_zipwith(xs,ys,f))

|(list_nil(),list_nil())=>list_nil()

//endof[list_zipwith]

Each element z in zs equals f(x, y), where x and y are the corresponding elements in xs and ys,

Page 197: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

respectively.Clearly,thisimplementationof list_zipwith isnottail-recursive.

Page 198: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:MergesortonLists(Redux)

I have previously presented an implementation of mergesort on lists that are formed with theconstructors list0_nil and list0_cons .Inthissection,Igiveanimplementationofmergesortonlistsformed with the constructors list_nil and list_cons . This implementation is based on the samealgorithmasthepreviousonebutitassignsatypetotheimplementedsortingfunctionthatguaranteesthefunctiontobelength-preserving,thatis,thefunctionalwaysreturnsalistofthesamelengthasthelistitsorts.

Thefollowingdefinedfunction merge combinestwoorderedlist(accordingtoagivenordering)intoasingleorderedlist:

//

typedeflte(a:t@ype)=(a,a)->bool

//

fun{

a:t@ype

}merge

{m,n:nat}.<m+n>.

(

xs0:list(a,m),ys0:list(a,n),lte:ltea

):list(a,m+n)=

case+xs0of

|list_nil()=>ys0

|list_cons(x,xs1)=>

(

case+ys0of

|list_nil()=>xs0

|list_cons(y,ys1)=>

ifx\ltey

thenlist_cons(x,merge(xs1,ys0,lte))

elselist_cons(y,merge(xs0,ys1,lte))

//endof[if]

)//endof[list_cons]

//endof[merge]

//

Clearly, the typeassigned to merge indicates that the function returnsa listwhose lengthequals thesumofthelengthsofthetwoinputlists.Notethataterminationmetricispresentforverifyingthatmerge isaterminatingfunction.

Thefollowingdefinedfunction mergesort mergesortsalistaccordingtoagivenordering:

Page 199: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

fun{

a:t@ype

}mergesort{n:nat}

(

xs:list(a,n),lte:ltea

):list(a,n)=let

funmsort

{n:nat}.<n,n>.

(

xs:list(a,n),n:intn,lte:ltea

):list(a,n)=

ifn>=2

thensplit(xs,n,lte,half(n),list_nil)elsexs

//endof[if]

//endof[msort]

andsplit

{n:int|n>=2}{i:nat|i<=n/2}.<n,i>.

(

xs:list(a,n-n/2+i)

,n:intn,lte:ltea,i:inti,xsf:list(a,n/2-i)

):list(a,n)=

ifi>0thenlet

val+list_cons(x,xs)=xs

in

split(xs,n,lte,i-1,list_cons(x,xsf))

endelselet

valn2=half(n)

valxsf=list_reverse<a>(xsf)//makesortingstable!

valxsf=list_of_list_vt(xsf)//linearlist->nonlinearlist

valxsf=msort(xsf,n2,lte)andxs=msort(xs,n-n2,lte)

in

merge(xsf,xs,lte)

end//endof[if]

//endof[split]

valn=list_length<a>(xs)

in

msort(xs,n,lte)

end//endof[mergesort]

Thetypeassignedto mergesort indicates that mergesort returnsa listof thesame lengthas its inputlist.Thetwoinnerfunctions msort and split aredefinedmutually recursively,and the terminationmetrics for them are pairs of natural numbers that are compared according to the standardlexicographic ordering on integer sequences. The type assigned to msort clearly indicates that itsintegerargument is required tobe the lengthof its list argument, andamismatchbetween the two

Page 200: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

surely results in a type-error. The type assigned to split is particularly informative, depicting arelation between the arguments and the return value of the function that can be of great help forsomeone trying to understand the code. The function list_reverse returns a linear list that is thereverseofitsinput,andthecastfunction list_of_list_vt turnsalinearlistintoanonlinearone(whileincuringnocostatrun-time).Iwillexplainwhatlinearlistsareelsewhere.

Pleasefindtheentirecodeinthissectionplussomeadditionalcodefortestingon-line.

Page 201: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

SequentialityofPatternMatching

InATS,patternmatching isperformedsequentiallyat run-time.Inotherwords,aclause isselectedonlyifagivenvaluematchesthepatternguardassociatedwiththisclausebutthevaluefailstomatchthe pattern associated with any clause ahead of it. Naturally, one may expect that the followingimplementationof list_zipwith alsotypechecks:

fun{

a1,

a2:t@ype

}{b:t@ype

}list_zipwith

{n:nat}

(

xs1:list(a1,n)

,xs2:list(a2,n)

,f:(a1,a2)-<cloref1>b

):list(b,n)=

case+(xs1,xs2)of

|(list_cons(x1,xs1),

list_cons(x2,xs2))=>

(

list_cons{b}(f(x1,x2),list_zipwith<a1,a2><b>(xs1,xs2,f))

)

|(_,_)=>list_nil(*void*)

//endof[list_zipwith]

This,however,isnotthecase.InATS,typecheckingclausesisdonenondeterministically(ratherthansequentially).Inthisexample,thesecondclausefailstotypecheckasitisdonewithouttheassumptionof thegivenpair (xs1, xs2) failing tomatch thepatternguardassociatedwith the firstclause.Thesecondclausecanbemodifiedslightlyasfollowstopasstypechecking:

|(_,_)=>>list_nil()

Theuseofthesymbol =>> (inplaceof => ) indicatestothetypechecker that thisclauseneedstobetypecheckedunder the sequentialityassumption that thegivenvaluematching itdoesnotmatch thepatternguardsassociatedwithanypreviousclauses.Therefore,whenthemodifiedsecondclauseistypechecked,itcanbeassumedthatthepair (xs1,xs2) matchingthepattern (_,_) mustmatchoneofthefollowingthreepatterns:

(list_cons(_,_),list_nil())

Page 202: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

(list_nil(),list_cons(_,_))

(list_nil(),list_nil())

Given that xs1 and xs2 are of the same length, the typechecker can readily infer that (xs1, xs2)

cannotmatcheitherof the first twopatterns.After these twopatternsare ruledout, typechecking isessentiallydoneasifthesecondclausewaswrittenasfollows:

|(list_nil(),list_nil())=>list_nil()

Onemaybewonderingwhytypecheckingclausesisnotrequiredtobedonesequentiallybydefault.Thesimplereasonisthatthisrequirement,iffullyenforced,canhaveagreatnegativeimpactontheefficiencyoftypechecking.Therefore,it isareasonabledesigntoprovidetheprogrammerwithanexplictmeans to occasionallymake use of the sequentiality assumption needed for typechecking aparticularclause.

Page 203: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:FunctionalRed-BlackTrees

Ared-blacktreeisdefinedasabinarytreesuchthateachnodeinitiscoloredredorblackandeverypathfromtheroottoaleafhasthesamenumberofblacknodeswhilecontainingnooccurrencesoftworednodesinarow.Clearly,thelengthofalongestpathineachred-blacktreeisboundedby2timesthelengthofashortestpathinit.Therefore,red-blacktreesareafamilyofbalancedtrees.Thenumberofblacknodesoccurringoneachpath ina red-black tree isoften referred toas theblackheightofthetree.

Formally,adatatypepreciselyforred-blacktreescanbedeclaredinATSasfollows:

#defineBLK0

#defineRED1

sortdefclr={c:nat|c<=1}

datatyperbtree

(a:t@ype+,int(*clr*),int(*bh*))=

|rbtree_nil(a,BLK,0)

|{c,cl,cr:clr|cl<=1-c;cr<=1-c}{bh:nat}

rbtree_cons(a,c,bh+1-c)of(intc,rbtree(a,cl,bh),a,rbtree(a,cr,bh))

//endof[rbtree]

Thecolorofatreeisthecolorofitsrootnodeorisblackifthetreeisempty.GivenatypeT,acolorC (represented by a integer) and an integer BH, the type rbtree(T, C, BH) is for red-black treescarryingelementsofthetypeTthatisofthecolorCandtheblackheightBH.

Whenimplementingvariousoperations(suchasinsertionanddeletion)onared-blacktree,weoftenneed to first construct intermediate trees that contain color violations caused by a red node beingfollowedbyanotherrednodeandthenemploytreerotationstofixsuchviolations.Thisneedmakestheabovedatatype rbtree toorigidasitcannotbeassignedtoanyintermediatetreescontainingcolorviolations.Toaddressthisissue,wecandeclare rbtree asfollows:

datatyperbtree

(

a:t@ype+

,int//color

,int//blackheight

,int//violations

)=

|rbtree_nil(a,BLK,0,0)of()

|{c,cl,cr:clr}{bh:nat}{v:int}

{c==BLK&&v==0||c==RED&&v==cl+cr}

Page 204: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

rbtree_cons(a,c,bh+1-c,v)of

(

intc,rbtree0(a,cl,bh),a,rbtree0(a,cr,bh)

)(*endof[rbtree_cons]*)

//endof[rbtree]

whererbtree0(a:t@ype,c:int,bh:int)=rbtree(a,c,bh,0)

Wecounteachoccurrenceoftworednodesinarowasonecolorviolation.GivenatypeT,acolorC(representedbyainteger),anintegerBHandanintegerV,thetype rbtree(T,C,BH,V) is for treescarryingelementsofthetypeTthatisofthecolorCandtheblackheightBHandcontainsexactlyVcolorviolations.Therefore,thetype rbtree(T,C,BH,0) isforvalidred-blacktrees(containingnocolorviolations).

Given a tree containing at most one color violation, an element and another tree containing noviolations,thefollowingoperationconstructsavalidred-blacktree:

fn{

a:t@ype

}insfix_l//rightrotationforfixingleftinsertion

{cl,cr:clr}{bh:nat}{v:nat}(

tl:rbtree(a,cl,bh,v),x0:a,tr:rbtree(a,cr,bh,0)

):[c:clr]rbtree0(a,c,bh+1)=let

#defineBBLK;#defineRRED;#defineconsrbtree_cons

in

case+(tl,x0,tr)of

|(cons(R,cons(R,a,x,b),y,c),z,d)=>

cons(R,cons(B,a,x,b),y,cons(B,c,z,d))//shallowrot

|(cons(R,a,x,cons(R,b,y,c)),z,d)=>

cons(R,cons(B,a,x,b),y,cons(B,c,z,d))//deeprotation

|(a,x,b)=>>cons(B,a,x,b)

end//endof[insfix_l]

Bysimplyreadingtheinterfaceof insfix_l ,wecanseethatthetwotreeargumentsarerequiredtobeofthesameblackheightbhforsomenaturalnumberbhandthereturnedtreeisoftheblackheightbh+1.

Thefollowingoperation insfix_r isjustthemirrorimageof insfix_l :

fn{

a:t@ype

}insfix_r//leftrotationforfixingrightinsertion

Page 205: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

{cl,cr:clr}{bh:nat}{v:nat}(

tl:rbtree(a,cl,bh,0),x0:a,tr:rbtree(a,cr,bh,v)

):[c:clr]rbtree0(a,c,bh+1)=let

#defineBBLK;#defineRRED;#defineconsrbtree_cons

in

case+(tl,x0,tr)of

|(a,x,cons(R,b,y,cons(R,c,z,d)))=>

cons(R,cons(B,a,x,b),y,cons(B,c,z,d))//shallowrot

|(a,x,cons(R,cons(R,b,y,c),z,d))=>

cons(R,cons(B,a,x,b),y,cons(B,c,z,d))//deeprotation

|(a,x,b)=>>cons(B,a,x,b)

end//endof[insfix_r]

Thepreparationforimplementinginsertiononared-blacktreeisalldonebynow,andwearereadytoseean implementationof insertionguaranteeing that the treeobtainedfrominsertinganelementintoagivenred-blacktreeisalwaysavalidred-blacktreeitself.Thisguaranteeispreciselycapturedinthefollowinginterfaceforinsertion:

extern

fun{

a:t@ype

}rbtree_insert

{c:clr}{bh:nat}

(

t:rbtree0(a,c,bh),x0:a,cmp:cmpa

):[bh1:nat]rbtree0(a,BLK,bh1)

Interestingly, this interface also implies that the tree returned by a call to rbtree_insert is alwaysblack.Thecodepresentedbelowgivesanimplementationof rbtree_insert :

implement{a}

rbtree_insert

(t,x0,cmp)=let

//

#defineBBLK

#defineRRED

#definenilrbtree_nil

#defineconsrbtree_cons

//

funins

{c:clr}{bh:nat}.<bh,c>.

(

t:rbtree0(a,c,bh),x0:a

):

[

Page 206: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

cl:clr;v:nat|v<=c

]rbtree(a,cl,bh,v)=

(

case+tof

|nil((*void*))=>

cons{..}{..}{..}{0}(R,nil,x0,nil)

|cons(c,tl,x,tr)=>let

valsgn=compare(x0,x,cmp)

in

ifsgn<0thenlet

val[cl,v:int]tl=ins(tl,x0)

in

ifc=Btheninsfix_l(tl,x,tr)

elsecons{..}{..}{..}{cl}(R,tl,x,tr)

//endof[if]

endelseifsgn>0thenlet

val[cr,v:int]tr=ins(tr,x0)

in

ifc=Btheninsfix_r(tl,x,tr)

elsecons{..}{..}{..}{cr}(R,tl,x,tr)

//endof[if]

endelset//endof[if]

end//endof[cons]

)(*endof[ins]*)

//

valt=ins(t,x0)

//

in

case+tofcons(R,tl,x,tr)=>cons(B,tl,x,tr)|_=>>t

end//endof[rbtree_insert]

Notethatthetypeassignedtotheinnerfunction ins issoinformativethatitliterallygivesanformalexplanation about the way in which insertion works on a red-black tree. Many a programmerimplementsred-blacktreesbysimplyfollowinganalgorithmwritteninsomeformatofpseudocodewhilehavinglittleunderstandingabouttheinnerworkingsofthealgorithm.Forinstance,iftheaboveinnerfunction ins isimplementedinC,fewprogrammersarelikelytoseethatthefunctionalwaysmaintain the black height of a given red-black tree after insertion but may introduce one colorviolationiftherootofthetreeisred.Ontheotherhand,knowingthisinvariantisessentialtogainingathoroughunderstandingoftheinsertionalgorithmonred-blacktrees.

Theinsertionoperationimplementedabovedoesnotinsertanelementifitisalreadyinthegivenred-blacktree.Itmaybedesirabletorequirethattheoperationinformthecallerifsuchacaseoccurs.Forinstance,anexceptioncanberaisedforthispurpose.Analternativeistogive rbtree_insert acall-by-

Page 207: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

referenceargumentsothataflagcanbereturnedinittoindicatewhethertheelementtobeinsertedisactuallyinserted.Iwillexplainelsewherewhatcall-by-referenceisandhowitissupportedinATS.

Oftendeletinganelementfromabinarysearchtreeissignificantlymoredifficulttoimplementthaninsertingone.Thisisespeciallysointhecaseofared-blacktree.Irefertheinterestedreadertothelibats libraryofATS for somecode implementingadeletionoperationon red-black trees that canguaranteebasedontypeseachtreereturnedbytheoperationbeingavalidred-blacktree(containingnocolorviolations).

Pleasefindtheentirecodeinthissectionplussomeadditionalcodefortestingon-line.

Page 208: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 209: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 210: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter11.Theorem-ProvinginATS/LFWithintheATSprogramminglanguagesystem,thereisacomponentnamedATS/LFforsupporting(interactive)therorem-proving.InATS/LF,theorem-provingisdonebyconstructingproofsastotalfunctionalprograms. Itwillsoonbecomeclear that thisstyleof theorem-provingcanbecombinedcohesivelywith functional programming to yield a programming paradigm that is considered thesignatureofATS:programmingwiththeorem-proving.Moreover,ATS/LFcanbeemployedtoencodevariousdeductionsystemsandtheirmeta-properties.

Pleasefindon-line thecodeemployedfor illustrationinthischapterplussomeadditionalcodefortesting.

Page 211: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

EncodingRelationsasDataprops

In thestaticsofATS, there isabuilt-insortprop for static terms that represent types forproofs.Astatictermofthesortpropcanalsobereferredtoasatypeormoreaccurately,aprop-typeorjustaprop.Adatapropcanbedeclaredinamannerthatismostlysimilartothedeclarationofadatatype.Forinstance,apropconstruct FIB isintroducedinthefollowingdatapropdeclaration:

dataprop

FIB(int,int)=

|FIB0(0,0)of()//[of()]canbedropped

|FIB1(1,1)of()//[of()]canbedropped

|{n:nat}{r0,r1:int}

FIB2(n+2,r0+r1)of(FIB(n,r0),FIB(n+1,r1))

//endof[FIB]

Thesortassignedto FIB is(int,int)->prop,indicatingthat FIB takestwostaticintegerstoformaprop-type.There are threedata (or proof) constructors associatedwith FIB : FIB0 , FIB1 and FIB2 ,whichareassignedthefollowingfunctiontypes(ormoreaccurately,prop-types):

FIB0 : ()->FIB(0,0)

FIB1 : ()->FIB(1,1)

FIB2 : {n:nat}{r0,r1:int}(FIB(n,r0),FIB(n+1,r1))->FIB(n+2,r0+r1)

Givenanaturalnumbernandanintegerr,itshouldbeclearthat FIB(n,r) encodestherelationfib(n)=r,wherefibisdefinedbythefollowingthreeequations:

fib(0)=0,and

fib(1)=1,and

fib(n+2)=fib(n)+fib(n+1)forn>=2.

Aproofvalueoftheprop FIB(n,r) canbeconstructedifandonlyiffib(n)equalsr.Forinstance,theproofvalue FIB2(FIB0(),FIB1()) isassignedtheprop FIB(2,1) ,attestingtofib(2)equaling1.

As another example of dataprop, the following declaration introduces a prop constructor MUL

togetherwiththreeassociatedproofconstructors:

datapropMUL(int,int,int)=

Page 212: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

|{n:int}MULbas(0,n,0)of()

|{m:nat}{n:int}{p:int}

MULind(m+1,n,p+n)ofMUL(m,n,p)

|{m:pos}{n:int}{p:int}

MULneg(~(m),n,~(p))ofMUL(m,n,p)

//endof[MUL]

Giventhreeintegersm,nandp,theprop MUL(m,n,p) encodestherelationm*n=p.Asfor MULbas ,MULind and MULneg ,theycorrespondtothefollowingthreeequations,respectively:

0*n=0foreveryintegern,and

(m+1)*n=m*n+nforeachpairofintegersmandn,and

(~m)*n=~(m*n)foreachpairofintegersmandn.

In other words, the dataprop declaration for MUL encodes the relation that represents the standardmultiplicationfunctiononintegers.

Itcanbereadilynoticedthattheprocessofencodingafunctionalrelation(i.e.,arelationrepresentingafunction)asadatapropisanalogoustoimplementingafunctioninalogicprogramminglanguagesuchasProlog.

Page 213: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ConstructingProofsasTotalFunctions

Theoremsarerepresentedastypes(ormoreaccurately,props)inATS/LF.Forinstance,thefollowingpropstatesthatintegermultiplicationiscommutative:

{m,n:int}{p:int}MUL(m,n,p)-<prf>MUL(n,m,p)

Constructing a proof for a theorem in ATS/LFmeans implementing a total value (which is mostlikelytobeatotalfunction)ofthetypethatistheencodingofthetheoreminATS/LF,wherebeingtotal means being pure and terminating. Please note that this style of theorem-proving may seemratherpeculiartothosewhohavenevertrieditbefore.

Asasimpleintroductoryexample,letusfirstconstructaprooffunctioninATS/LFthatisgiventhefollowinginterface:

prfunmul_istot{m,n:int}():[p:int]MUL(m,n,p)

Thekeyword prfun indicates that the interface is for a proof function (in contrast to a non-prooffunction).Notethat mul_istot isdeclaredtobeofthefollowingtype(ormoreaccurately,prop):

{m,n:int}()-<prf>[p:int]MUL(m,n,p)

whichessentiallystatesthatintegermultiplicationisatotalfunction:Givenanytwointegersmandn,there exists an integer p such thatm, n and p are related according to the structurally inductivelydefinedrelation MUL .Thefollowingcodegivesanimplementationof mul_istot :

primplement

mul_istot{m,n}()=let

//

prfunistot

{m:nat;n:int}.<m>.():[p:int]MUL(m,n,p)=

sifm>0thenMULind(istot{m-1,n}())elseMULbas()

//endof[istot]

//

in

sifm>=0thenistot{m,n}()elseMULneg(istot{~m,n}())

end//endof[mul_istot]

Notethatthekeyword primplement (insteadof implement )initiatestheimplementationofaproof.Theinner proof function istot encodes a proof showing that there exists an integer p for any givennaturalnumbermandintegernsuchthatm,nandparerelated(accordingto MUL ).Thekeyword sif

Page 214: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

isusedforformingaconditional(proof)expressioninwhichthetestisastaticexpression.Theproofencodedby istot proceedsbyinductiononm;ifm>0holds,thenthereexistsanintegerp1suchthatm-1,nandp1arerelatedbyinductionhypothesis(onm-1)andthusm,nandparerelatedforp=p1+naccordingtotheruleencodedby MULind ; ifm=0, thenm,nandparerelatedforp=0.Theproofencodedbytheimplementationof mul_istot goeslikethis: ifmisanaturalnumber, thenthelemma proven by istot shows thatm, n and some p are related; if m is negative, then the samelemmashowsthat~m,nandp1arerelatedforsomeintegerp1andthusm,nandparerelatedforp=~p1accordingtotheruleencodedby MULneg .

Asanotherexampleoftheorem-provinginATS/LF,aprooffunctionofthename mul_isfun isgivenasfollows:

prfnmul_isfun

{m,n:int}{p1,p2:int}

(

pf1:MUL(m,n,p1),pf2:MUL(m,n,p2)

):[p1==p2]void=let

prfunisfun

{m:nat;n:int}{p1,p2:int}.<m>.

(

pf1:MUL(m,n,p1),pf2:MUL(m,n,p2)

):[p1==p2]void=

case+pf1of

|MULind(pf1prev)=>let

prvalMULind(pf2prev)=pf2inisfun(pf1prev,pf2prev)

end//endof[MULind]

|MULbas()=>let

prvalMULbas()=pf2in()

end//endof[MULbas]

//endof[isfun]

in

case+pf1of

|MULneg(pf1nat)=>let

prvalMULneg(pf2nat)=pf2inisfun(pf1nat,pf2nat)

end//endof[MULneg]

|_(*non-MULneg*)=>>isfun(pf1,pf2)

end//endof[mul_isfun]

Thekeyword prfn isusedfordefininganon-recursiveprooffunction,and thekeyword prval forintroducingbindingsthatrelatenamestoproofexpressions,thatis,expressionsofprop-types.Asfaras pattern matching exhaustiveness is concerned, prval is equivalent to val+ (as proofs cannotcontainanyeffectssuchasfailuresofpatternmatching).

Page 215: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

What mul_isfun provesisthattherelation MUL isfunctionalonitsfirsttwoarguments:Ifm,nandp1arerelatedaccordingto MUL andm,nandp2arealsorelatedaccordingto MUL , thenp1andp2areequal.Thestatementisfirstprovenbytheinnerprooffunction isfun undertheassumptionthatmisanatural number, and then the assumption is dropped. Let us now take a look at the first matchingclauseinthebodyof isfun .Iftheclauseischosen,then pf1 matchesthepattern MULind(pf1prev) andthus pf1prev isofthetype MUL(m1,n1,q1) forsomenaturalnumberm1andintegern1andintegerp1suchthatm=m1+1,n=n1,andp1=q1+n1.Thismeansthat pf2 mustbeoftheform MULind(pf2prev) forsome pf2prev ofthetype MUL(m2,n2,q2) suchthatm2+1=m,n2=nandp2=q2+n2.Bycalling isfunon pf1prev and pf2prev ,which amounts to invoking the inductionhypothesis onm-1,we establishq1=q2, which implies p1=p2. The second matching clause in the body of isfun can be readilyunderstood,whichcorrespondstothebasecaseintheinductiveproofencodedby isfun .

Page 216: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:DistributivityofMultiplication

Thedistributivityofmultiplicationoveradditionmeansthatthefollowingequationholds

m*(n1+n2)=m*n1+m*n2

form,n1andn2rangingoverintegers.Adirectencodingoftheequationisgivenbythefollowing(proof)functioninterface:

//

prfun

mul_distribute

{m,n1,n2:int}{p1,p2:int}

(MUL(m,n1,p1),MUL(m,n2,p2)):MUL(m,n1+n2,p1+p2)

//

Plainlyspeaking,theencodingstatesthattheproductofmand(n1+n2)isp1+p2iftheproductofmand n1 is p1 and the product ofm and n2 is p2.An implementation of mul_distribute is given asfollows:

primplement

mul_distribute

{m,n1,n2}{p1,p2}

(pf1,pf2)=let

//

prfun

auxnat

{m:nat}{p1,p2:int}.<m>.

(

pf1:MUL(m,n1,p1),pf2:MUL(m,n2,p2)

):MUL(m,n1+n2,p1+p2)=

(

case+(pf1,pf2)of

|(MULbas(),MULbas())=>MULbas()

|(MULindpf1,MULindpf2)=>MULind(auxnat(pf1,pf2))

)(*endof[auxnat]*)

//

in

//

sif

m>=0

then(

auxnat(pf1,pf2)

)//endof[then]

Page 217: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

elselet

prvalMULneg(pf1)=pf1

prvalMULneg(pf2)=pf2

in

MULneg(auxnat(pf1,pf2))

end//endof[else]

//

end//endof[mul_distribute]

The inner function auxnat encodes a straighforward proof based on mathematical induction thatestablishesthefollowingequation:

m*(n1+n2)=m*n1+m*n2

for m ranging over natural numbers and n1 and n2 ranging over integers. The functionmul_distribute canthenbeimplementedimmediatelybasedon auxnat .

Page 218: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:CommutativityofMultiplication

Thecommutativityofmultiplicationmeansthatthefollowingequationholds

m*n=n*m

for m and n ranging over integers. A direct encoding of this equation is given by the following(proof)functioninterface:

//

prfun

mul_commute{m,n:int}{p:int}(MUL(m,n,p)):MUL(n,m,p)

//

Animplementationof mul_commute isgivenasfollows:

primplmnt

mul_commute

{m,n}{p}(pf0)=let

//

prfun

auxnat

{m:nat}

{p:int}.<m>.

(

pf:MUL(m,n,p)

):MUL(n,m,p)=

(

case+pfof

|MULbas()=>mul_nx0_0{n}()

|MULind(pf1)=>

mul_distribute(auxnat(pf1),mul_nx1_n{n}())

//endof[MULind]

)(*endof[auxnat]*)

//

in

//

sif

m>=0

thenauxnat(pf0)

elselet

prvalMULneg(pf1)=pf0inmul_neg_2(auxnat(pf1))

end//endof[else]

//

end//endof[mul_commute]

Page 219: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

wherethefollowingprooffunctionsarecalled:

//

prfun

mul_nx0_0{n:int}():MUL(n,0,0)//n*0=0

//

prfun

mul_nx1_n{n:int}():MUL(n,1,n)//n*1=n

//

prfun

mul_neg_2

{m,n:int}{p:int}(MUL(m,n,p)):MUL(m,~n,~p)//m*(~n)=~(m*n)

//

The inner function auxnat encodes a straighforward proof based on mathematical induction thatestablishesthefollowingequation:

m*n=n*m

formrangingovernaturalnumbersandnrangingoverintegers.Thefunction mul_commute canthenbeimplementedimmediatelybasedon auxnat .

Page 220: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

AlgebraicDatasorts

Adatasortisrathersimilartoadataype.However,theformerisdeclaredinthestaticsofATSwhilethelatterinthedynamicsofATS.Toseeatypicalneedfordatasorts,letustrytoencodeatheoreminATSstating that s is strictly less than2h if s andhare the sizeandheight, respectively,of agivenbinarytree.Torepresentbinarytreesinthestatics,wefirstdeclareadatasortasfollows:

datasorttree=Eof()|Bof(tree,tree)

Thenameofthedeclareddatasortis tree andtherearetwoconstructorassociatedwithit: E and B ,whereEformstheemptytreeandBformsatreebyjoiningtwogiventrees.Forinstance, B(E(),E())isastatictermofthesort tree thatrepresentsasingletontree,thatis,atreeconsistingofexactlyonenode.PleasenotethatthetreesformedbyEandBarereallyjusttreeskeletonscarryingnodata.

Wenowdeclaretwodatapropsasfollowsforcapturingthenotionofsizeandheightoftrees:

dataprop

SZ(tree,int)=

|SZE(E(),0)of()

|{tl,tr:tree}{sl,sr:nat}

SZB(B(tl,tr),1+sl+sr)of(SZ(tl,sl),SZ(tr,sr))

//endof[SZ]

dataprop

HT(tree,int)=

|HTE(E(),0)of()

|{tl,tr:tree}{hl,hr:nat}

HTB(B(tl,tr),1+max(hl,hr))of(HT(tl,hl),HT(tr,hr))

//endof[HT]

Givenatreetandanintegers,SZ(t,s)encodestherelationthatthesizeoftequalss.Similiarly,givenatreetandanintegerh,HZ(t,h)encodestherelationthattheheightoftequalsh.

As the power function (of base 2) is not available in the statics ofATS,we declare a dataprop asfollowstocaptureit:

dataprop

POW2(int,int)=

|POW2bas(0,1)

|{n:nat}{p:int}POW2ind(n+1,p+p)ofPOW2(n,p)

//endof[POW2]

Page 221: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Giventwointegershandp,POW2(h,p)encodestherelationthat2hequalsp.

Itshouldbeclearbynowthatthefollowingprooffunctioninterfaceencodesthetheoremstatingthatsisstrictlylessthan2hifsandharethesizeandheightofagivenbinarytree:

prfun

lemma_tree_size_height

{t:tree}{s,h:nat}{p:int}

(

pf1:SZ(t,s),pf2:HT(t,h),pf3:POW2(h,p)

):[s<p]void//endof[prfun]

Letusnowconstructanimplementationofthisprooffunctionasfollows.

Wefirstestablishsomeelementarypropertiesonthepowerfunction(ofbase2):

prfun

pow2_istot

{h:nat}.<h>.():[p:int]POW2(h,p)=

sifh==0

thenPOW2bas()elsePOW2ind(pow2_istot{h-1}())

//endof[sif]

//endof[pow2_istot]

prfun

pow2_pos

{h:nat}{p:int}.<h>.

(pf:POW2(h,p)):[p>0]void=

case+pfof

|POW2bas()=>()|POW2ind(pf1)=>pow2_pos(pf1)

//endof[pow2_pos]

prfun

pow2_inc

{h1,h2:nat|h1<=h2}{p1,p2:int}.<h2>.

(pf1:POW2(h1,p1),pf2:POW2(h2,p2)):[p1<=p2]void=

case+pf1of

|POW2bas()=>pow2_pos(pf2)

|POW2ind(pf11)=>let

prvalPOW2ind(pf21)=pf2inpow2_inc(pf11,pf21)

end//endof[POW2ind]

//endof[pow2_inc]

Clearly, pow2_istot showsthattherelationencodedbythedataprop POW2 isatotalrelation; pow2_posprovesthatthepowerofeachnaturalnumberispositive; pow2_inc establishesthatthepowerfunction

Page 222: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

isincreasing.

Thefunction lemma_tree_size_height canbeimplementedasfollows:

primplement

lemma_tree_size_height

(pf1,pf2,pf3)=let

//

prfun

lemma{t:tree}

{s,h:nat}{p:int}.<t>.

(

pf1:SZ(t,s)

,pf2:HT(t,h)

,pf3:POW2(h,p)

):[p>s]void=

(

scasetof

|E()=>let

prvalSZE()=pf1

prvalHTE()=pf2

prvalPOW2bas()=pf3

in

//nothing

end//endof[E]

|B(tl,tr)=>let

prvalSZB(pf1l,pf1r)=pf1

prvalHTB{tl,tr}{hl,hr}(pf2l,pf2r)=pf2

prvalPOW2ind(pf31)=pf3

prvalpf3l=pow2_istot{hl}()

prvalpf3r=pow2_istot{hr}()

prval()=lemma(pf1l,pf2l,pf3l)

prval()=lemma(pf1r,pf2r,pf3r)

prval()=pow2_inc(pf3l,pf31)

prval()=pow2_inc(pf3r,pf31)

in

//nothing

end//endof[B]

)(*endof[lemma]*)

//

in

lemma(pf1,pf2,pf3)

end//endof[lemma_tree_size_height]

Theinnerfunction lemma ,whichisgivenaterminationmetricconsistingofastatictermofthesort

Page 223: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

tree ,correspondstoaproofbasedonstructuralinduction(wheretheinvolvedstructureisthebinarytree t ).Given two terms t1 and t2 of the sort tree , t1 is (strictly) less than t2 if t1 is a (proper)substructureof t2.Evidently, this isawell-foundedordering.Thekeyword scase isused to formadynamic expression that does case-analysis on a static term (built by constructors associated withsomedeclareddatasort).Sotherelationbetween sif and scase isessentiallyparalleltothatbetweenif and case .Pleasefindtheentiretyoftheabovecodeon-line.

Page 224: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:EstablishingPropertiesonBraunTrees

Asstatedpreviously in thisbook,abinary tree isaBraun tree if it isemptyor if its leftandrightsubtreesareBrauntreesandthesizeoftheleftoneminusthesizeoftherightoneiseither0or1.Formally,wecandeclarethefollowingdataprop isBraun tocapturethenotionofBrauntrees:

dataprop

isBraun(tree)=

|isBraunE(E)of()

|{tl,tr:tree}

{sl,sr:nat|sr<=sl;sl<=sr+1}

isBraunB(

B(tl,tr))of(isBrauntl,isBrauntr,SZ(tl,sl),SZ(tr,sr)

)//endof[isBraunB]

//endof[isBraun]

We first prove that there exists a Braun tree of any given size. This property can be encoded asfollowsinATS:

prfunlemma_existence{n:nat}():[t:tree](isBraun(t),SZ(t,n))

Literally, the typeassigned to lemma_existence means that there exists a tree t for anygivennaturalnumbernsuchthattisaBrauntreeandthesizeoftisn.Thefollowingcodegivesanimplementationof lemma_existence :

primplement

lemma_existence

{n}((*void*))=let

//

prfun

lemma{n:nat}.<n>.

(

//argless

):[t:tree](isBraun(t),SZ(t,n))=

sifn==0

then(isBraunE(),SZE())

elselet

stadefnl=n/2

stadefnr=n-1-nl

val(pfl1,pfl2)=lemma{nl}((*void*))

and(pfr1,pfr2)=lemma{nr}((*void*))

in

(isBraunB(pfl1,pfr1,pfl2,pfr2),SZB(pfl2,pfr2))

Page 225: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

end//endof[else]

//endof[sif]

//

in

lemma{n}((*void*))

end//endof[lemma_existence]

Notethat stadef isakeyword inATSfor introductingastaticbindingbetweenanameandastaticterm(ofanysort). Ifoneprefers, thiskeywordcanbechosen to replace thekeyword typedef (forintroducinganameandastatictermofthesort t@ype ).

Nextweshow that twoBraun treesof thesamesizeare identical.Thispropertycanbeencodedasfollows:

prfun

lemma_unicity

{n:nat}{t1,t2:tree}

(

pf1:isBraunt1,pf2:isBraunt2,pf3:SZ(t1,n),pf4:SZ(t2,n)

):EQ(t1,t2)//endof[lemma_unicity]

where EQ isaprop-constructorintroducedbythefollowingdatapropdeclaration:

datapropEQ(tree,tree)=

|EQE(E,E)of()

|{t1l,t1r:tree}{t2l,t2r:tree}

EQB(B(t1l,t1r),B(t2l,t2r))of(EQ(t1l,t2l),EQ(t1r,t2r))

//endof[EQ]

Clearly, EQ is the inductively defined equality on trees. An implementation of the proof functionlemma_unicity ispresentedasfollows:

primplement

lemma_unicity

(pf1,pf2,pf3,pf4)=let

prfunlemma{n:nat}{t1,t2:tree}.<n>.

(

pf1:isBraunt1,pf2:isBraunt2,pf3:SZ(t1,n),pf4:SZ(t2,n)

):EQ(t1,t2)=

sifn==0

thenlet

prvalSZE()=pf3andSZE()=pf4

prvalisBraunE()=pf1andisBraunE()=pf2

in

Page 226: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

EQE()

end//endof[then]

elselet

prvalSZB(pf3l,pf3r)=pf3

prvalSZB(pf4l,pf4r)=pf4

prvalisBraunB(pf1l,pf1r,pf1lsz,pf1rsz)=pf1

prvalisBraunB(pf2l,pf2r,pf2lsz,pf2rsz)=pf2

prval()=SZ_istot(pf1lsz,pf3l)and()=SZ_istot(pf1rsz,pf3r)

prval()=SZ_istot(pf2lsz,pf4l)and()=SZ_istot(pf2rsz,pf4r)

prvalpfeql=lemma(pf1l,pf2l,pf3l,pf4l)

prvalpfeqr=lemma(pf1r,pf2r,pf3r,pf4r)

in

EQB(pfeql,pfeqr)

end//endof[else]

//endof[sif]

in

lemma(pf1,pf2,pf3,pf4)

end//endof[lemma_unicity]

Notethattheprooffunction SZ_istot inthisimplementationof lemma_unicity isgiventhefollowinginterface:

prfun

SZ_istot{t:tree}{n1,n2:int}

(pf1:SZ(t,n1),pf2:SZ(t,n2)):[n1==n2]void

whichsimplystatesthat SZ isafunctionalrelationwithrespecttoitsfirstparameter,thatis,thereisatmostonenforeverygiventsuchthattandnarerelatedaccordingto SZ .Clearly,themathematicalproofcorrespondingtothisimplementationisofinductiononthesizenofthetwogiventreest1andt2.Inthebasecasewherenis0,t1andt2areequalastheybotharetheemptytree.Intheinductivecasewheren>0,itisproventhatn1landn2lareofthesamevaluewheren1landn2larethesizesoftheleftsubtreesoft1andt2,respecitvely;similarly,itisalsoproventhatn1randn2rareofthesamevaluewheren1r andn2r are the sizesof the right subtreesof t1 and t2, respectively; by inductionhypothesisonn1l,theleftsubstreesoft1andt2arethesame;byinductionhypothesisonn1r,therightsubstreesoft1andt2arethesame;bythedefinitionoftreeequality(encodedby EQ ),t1andt2arethesame.

As a comparison, the following code gives another implementation of lemma_unicity that is of adifferent(andratherunusual)style:

primplement

lemma_unicity

Page 227: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

(pf1,pf2,pf3,pf4)=let

//

prfun

lemma{n:nat}{t1,t2:tree}.<t1>.

(

pf1:isBraunt1,pf2:isBraunt2,pf3:SZ(t1,n),pf4:SZ(t2,n)

):EQ(t1,t2)=

case+(pf1,pf2)of

//

|(isBraunE(),isBraunE())=>EQE()

//

|(isBraunB(pf11,pf12,pf13,pf14),

isBraunB(pf21,pf22,pf23,pf24))=>let

//

prvalSZB(pf31,pf32)=pf3

prvalSZB(pf41,pf42)=pf4

//

prval()=SZ_istot(pf13,pf31)

prval()=SZ_istot(pf23,pf41)

//

prval()=SZ_istot(pf14,pf32)

prval()=SZ_istot(pf24,pf42)

//

prvalpfeq1=lemma(pf11,pf21,pf31,pf41)

prvalpfeq2=lemma(pf12,pf22,pf32,pf42)

in

EQB(pfeq1,pfeq2)

end

//

|(isBraunE_,isBraunB_)=/=>

letprvalSZE_=pf3andSZB_=pf4in(*none*)end

|(isBraunB_,isBraunE_)=/=>

letprvalSZB_=pf3andSZE_=pf4in(*none*)end

//

in

lemma(pf1,pf2,pf3,pf4)

end//endof[lemma_unicity]

Thisimplementationcorrespondstoaproofbyinductiononthestructureofthegiventreet1.Notethattheuseofthespecialsymbol =/=> ,whichisakeywordinATS,istoindicatetothetypecheckerofATS that the involved clause of pattern matching is unreachable: It is the responsibility of theprogrammertoestablishthefalsehoodontheright-handsideoftheclause.Pleasefindtheentiretyoftheabovecodeon-line.

Page 228: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Programmer-CentricTheorem-Proving

IhavesofarpresentedseveralformalproofsinATS.However,constructingsuchformalproofsisatmostasecondaryissueinATS.IfIcompareATSwiththeorem-provingsystemssuchasIsabelleandCoq, I would like to state emphatically that the design for theorem-proving in ATS takes afundamentally different view of theorem-proving. In particular, theorem-proving inATS does nottakeafoundationalapproachthatestablishesthevalidityofatheorembyreducingittothevalidityofaminimalsetofaxiomsandrules.Instead,theorem-provinginATSismostlydoneinasemi-formalmannerand itsprimarypurpose is togreatlydiminish thechanceofaprogrammermakinguseofincorrect assumptions or claims. In this regard, theorem-proving in ATS is rather similar tocontructinginformalpaper-and-pencilproofs(inmathematicsandelsewhere).Irefertothisstyleoftheorem-provinginATSasbeingprogrammer-centric.Inordertoallowthereadertoobtainamoreconcrete feel as towhat this styleof theorem-proving is like, Ipresent in the restof this sectionasimplebuttellingexampleofprogrammer-centrictheorem-proving.

Suppose we are to prove that the square of any rational number cannot equal 2. Note that thisstatementisabitweakerthantheonestatingthatthesquarerootof2isirrationalasthelatterassumestheveryexistenceofthesquarerootof2.Letusfirstsketchaninformalproofasfollows.

Suppose(m/n)2=2forsomepositivenumbersmandn.Clearly, thismeans(m)2=2(n)2, implyingmbeinganevennumber.Letm=2m2.Wehave(2m2)2=2(n)2,implying(n/m2)2=2.Clearly,m>n>m2

holds. If we assume that m is the least positive number satisfying (m/n)2=2 for some n, then acontradiction is reached as n satisfies the same property. Therefore, there is no rational numberwhosesquareequals2.Clearly,thisproofstillholdsifthenumber2isreplacedwithanotherprimenumber.

TheprimaryargumentintheaboveinformalproofcanbeencodedinATSasfollows:

//

extern

prfun

mylemma_main

{m,n,p:int|m*m==p*n*n}(PRIME(p)):[m2:nat|n*n==p*m2*m2]void

//

primplmnt

mylemma_main

{m,n,p}(pfprm)=let

prvalpfeq_mm_pnn=

eqint_make{m*m,p*n*n}()

prval()=square_is_nat{m}()

Page 229: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

prval()=square_is_nat{n}()

prval()=lemma_PRIME_param(pfprm)

prval

pfmod1=

lemma_MOD0_intr{m*m,p,n*n}()

prval

pfmod2=mylemma1{m,p}(pfmod1,pfprm)

prval

[m2:int]

EQINT()=

lemma_MOD0_elim(pfmod2)

prvalEQINT()=pfeq_mm_pnn

prval()=

__assert{p}{p*m2*m2,n*n}()where

{

externprfun__assert{p:pos}{x,y:int|p*x==p*y}():[x==y]void

}(*endof[where]*)//endof[prval]

in

#[m2|()]

end//endof[mylemma_main]

//

The interface for mylemma_main states that (m)2=p(n)2 implies (n)2=p(m2)2 for somenatural numberm2.

Giventwointegersmandp, MOD0(m,p) meansthatmequalstheproductofpandqforsomenaturalnumberq.Thismeaningisencodedintothefollowingtwoprooffunctions:

//

prfun

lemma_MOD0_intr{m,p,q:nat|m==p*q}():MOD0(m,p)

//

prfun

lemma_MOD0_elim{m,p:int}(MOD0(m,p)):[q:nat]EQINT(m,p*q)

//

where EQINT isadatapropdeclaredasfollows:

datapropEQINT(int,int)={x:int}EQINT(x,x)

Giventwointegersxandy, EQINT(x,y) simplymeansthatxequalsy.Also,thefunction eqint_make isassginedtheinterfacebelow:

prfuneqint_make{x,y:int|x==y}((*void*)):EQINT(x,y)

Page 230: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Givenanintegerp, PRIME(p) meansthatpisaprimenumber.Thefollowingtwoprooffunctionsarecalledintheaboveimplementationof mylemma_main :

//

prfunlemma_PRIME_param{p:int}(PRIME(p)):[p>=2]void

//

prfunmylemma1{n,p:int}(MOD0(n*n,p),PRIME(p)):MOD0(n,p)

//

Theprooffunction mylemma1 encodesapropositionstatingthatpdividesnifpdividesthesquareofnandpisalsoaprimenumber.Igivenoimplementationof mylemma1 asIseetheencodedpropositiontobeobviouslytrue.Certainly,thisisakindofprogrammer-centricjudgment.

Onemayfindthatthefollowingdeclarationintheimplementationof mylemma_main looksmysterious:

prvalEQINT()=pfeq_mm_pnn

Note that pfeq_mm_pnn is of the prop EQINT(m*m, p*(n*n)) . Also,m equaling p*m2 for some naturalnumber m2 is available when the above declaration is typechecked. This means that the equalitybetween(p*m2)2 and p*(n)2 is added into the current store of (static) assumptions after the abovedeclarationistypechecked.

Please findon-line the entirety of an encoded proof showing that there exists no rational numberwhosesquareequals2.

Page 231: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 232: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 233: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter 12. Programming with Theorem-ProvingProgrammingwithTheorem-Proving(PwTP)isarichandbroadprogrammingparadigmthatallowscohesive constructionof programs andproofs in a syntactically intwinedmanner.The support forPwTPinATSisasignatoryfeatureofATS,andthenoveltyofATSlargelystemsfromit.Forpeoplewho are familiar with the so-called Curry-Howard isomorphism, I emphasize that PwTP as issupported in ATS makes little, if any, essential use of this isomorphism (between proofs andprograms):ThedynamicsofATSinwhichprogramsarewritteniscertainlynotpureandtheproofsencoded inATS/LFarenot required tobeconstructive, either.However, thatproofconstruction inATS can be done in a style of (functional) programming is fundamentally important in terms ofsyntaxdesign forATS, for theneed tocombineprogramswithproofswouldotherwisebegreatlymorechallenging.

In this chapter, I will present some simple but convincing examples to illustrate the power andflexibilityofPwTPasissupportedinATS.However,therealshowcaseforPwTPwillnotarriveuntilaftertheintroductionoflineartypesinATS,whenlinearproofscanbecombinedwithprogramstotrackandsafelymanipulate resourcessuchasmemoryandobjects (e.g, filehandles). Inparticular,PwTPistoformthecornersoneofthesupportforimperativeprogramminginATS.

Pleasefindon-line thecodeemployedfor illustrationinthischapterplussomeadditionalcodefortesting.

Page 234: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

CircumventingNonlinearConstraints

The constraint-solver of ATS is of rather diminished power. In particular, constraints containingnonlinear integer terms (e.g., those involving the use of multiplication (of variables)) areimmediately rejected.Thisweaknessmust be properly addressed for otherwise itwould become acrippling limitation on practicality of the type system of ATS. I now use a simple example todemonstratehowtheorem-provingcanbeemployed tocircumvent theneedforhandlingnonlinearconstraintsdirectly.

Afunctiontemplate list_concat isimplementedasfollows:

//

//[list_concat]doestypecheckinATS2

//[list_concat]doesnottypecheckinATS1

//

fun{

a:t@ype

}list_concat{m,n:nat}

(

xss:list(list(a,n),m)

):list(a,m*n)=

case+xssof

|list_nil()=>list_nil()

|list_cons(xs,xss)=>list_append<a>(xs,list_concatxss)

//endof[list_concat]

wheretheinterfacefor list_append isgivenbelow:

fun{

a:t@ype

}list_append{n1,n2:nat}

(xs:list(a,n1),ys:list(a,n2)):list(a,n1+n2)

Given a list xss of length m in which each element is of the type list(T,n) for some type T,list_concat<T>(xss) constructs a list of the type list(T,m*n) .When the firstmatching clause in thecode for list_concat is typechecked, a constraint is generated that is essentially like the followingone:

m=m1+1implyingn+(m1*n)=m*nholdsforallnaturalnumbersm,m1andn.

Thiscontraintmaylooksimple,butitwasoncerejectedbytheATSconstraintsolverasitcontains

Page 235: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

nonlinear integer terms (e.g., m1*n and m*n ). In order to overcome (or rather circumvent) thelimitation,wecanmakeuseoftheorem-proving.Anotherimplementationof list_concat isgivenasfollows:

fun{

a:t@ype

}list_concat{m,n:nat}

(

xss:list(list(a,n),m)

):[p:nat](MUL(m,n,p)|list(a,p))=

(

//

case+xssof

|list_nil()=>

(MULbas()|list_nil())

|list_cons(xs,xss)=>let

val(pf|res)=list_concat(xss)

in

(MULindpf|list_append<a>(xs,res))

end//endof[list_cons]

//

)(*endof[list_concat]*)

Givenalist xss ofthetype list(list(T,n),m) , list_concat(xss) nowreturnsapair (pf | res) suchthat pf isaproofoftheprop-type MUL(m,n,p) forsomenaturalnumber p and res isalistofthetypelist(T,p) ,wherethesymbolbar(|)isusedtoseparateproofsfromvalues.Inotherwords, pf actsasawitnesstotheequality p=m*n .Afterprooferasureisperformed,thisimplementationof list_concatis essentially translated into the previous one (as far as dynamic semantics is concerned). Inparticular,thereisnoneedforproofconstructionatrun-time.

Page 236: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:SafeMatrixSubscripting

Internally,amatrixof thedimensionmbynisrepresentedasanarrayof thesizem*n.Formatrixsubscripting,weneedtoimplementafunctiontemplateofthefollowinginterface:

extern

fun{

a:t@ype

}matrix_get

{m,n:int}{i,j:nat|i<m;j<n}

(A:arrayref(a,m*n),col:intn,i:inti,j:intj):a

//endof[matrix_get]

Assumethatthematrixisrepresentedintherow-majorstyle.Thentheelementindexedbyiandjinthematrixistheelementindexedbyi*n+jinthearraythatrepresentsthematrix,whereiandjarenaturalnumberslessthanmandn,respectively.However,thefollowingimplementationfailstopasstypechecking:

implement

{a}(*tmp*)

matrix_get(A,n,i,j)=A[i*n+j]//itfailstotypecheck!!!

ThesimplereasonforthisfailureisduetotheATSconstraintsolvernotbeingabletoautomaticallyverify that i*n+j is a natural number strictly less thanm*n.An implementation of matrix_get thattypecheckscanbegivenasfollows:

implement

{a}(*tmp*)

matrix_get

{m,n}{i,j}

(A,n,i,j)=let

//

val(pf|_in_)=imul2(i,n)

//

prval((*void*))=mul_elim(pf)

prval((*void*))=mul_nat_nat_nat(pf)

prval((*void*))=mul_gte_gte_gte{m-1-i,n}()

//

in

A[_in_+j]

end//endof[matrix_get]

wherethefunctionscalledinthebodyof matrix_get areassignedthefollowinginterfaces:

Page 237: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

//

fun

imul2{i,j:int}

(inti,intj):<>[ij:int](MUL(i,j,ij)|intij)

//

prfun

mul_elim

{i,j:int}{ij:int}(pf:MUL(i,j,ij)):[i*j==ij]void

//

prfun

mul_nat_nat_nat

{i,j:nat}{ij:int}(pf:MUL(i,j,ij)):[ij>=0]void

//

prfun

mul_gte_gte_gte

{m,n:int|m>=0;n>=0}((*void*)):[m*n>=0]void

//

Assume that m and n are natural numbers and i and j are natural numbers less than m and n,respectively. The proof code employed in the implementation of matrix_get to show i*n+j <m*nproves(m-1-i)*n>=0,whichclearlyimpliesm*n>=i*n+n>i*n+j.

Notethatthereareavarietyofprooffunctionsdeclaredinarith_prf.satsforhelpingprovetheoremsinvolving arithmetic operations. For examples of proof construction in ATS, please find theimplementationofsomeoftheseprooffunctionsinarith_prf.dats.

Theentiretyoftheabovepresentedcodeisavailableon-line.

Page 238: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

SpecifyingwithEnhancedPrecision

Theintegeradditionfunctioncanbeassignedthefollowing(dependent)typeinATStoindicatethatitreturnsthesumofitstwointegerarguments:

{i,j:int}(int(i),int(j))->int(i+j)

Thistypegivesafullspecificationofintegeradditionastheonly(terminating)functionthatcanbegiven the type is the integer addition function. However, the factorial function, which yields theproduct of the first n positive integers when applied to a natural number n, cannot be given thefollowingtype:

{n:nat}int(n)->int(fact(n))

as fact ,whichreferstothefactorialfunction,doesnotexistinthestaticsofATS.Evidently,ahighlyinteresting and relevant question is whether a type can be formed in ATS that fully captures thefunctional relationspecifiedby fact ?Theanswer is affirmative.Wecannotonlyconstruct suchatypebutalsoassignittoa(terminating)functionimplementedinATS.

Letusrecallthatthefactorialfunctioncanbedefinedbythefollowingtwoequations:

fact(0)=1

fact(n)=n*fact(n-1)(foralln>0)

Naturally, these equations can be encoded by the constructors associated with the dataprop FACT

declaredasfollows:

dataprop

FACT(int,int)=

|FACTbas(0,1)

|{n:nat}{r1,r:int}

FACTind(n,r)of(FACT(n-1,r1),MUL(n,r1,r))

//endof[FACT]

Notethatforanygivennaturalnumbernandintegerr, FACT(n,r) canbeassignedtoaproofifandonlyif fact(n) equalsr.Therefore,thefollowingtype:

{n:nat}int(n)->[r:int](FACT(n,r)|int(r))

canonlybeassignedtoafunctionthat,ifappliedtoanaturalnumbern,returnsaproofandaninteger

Page 239: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

suchthat theproofattests to theintegerbeingequal to fact(n) .For instance, thefollowingdefinedfunction ifact isassignedthistype:

//

fun

ifact

{n:nat}.<n>.

(

n:int(n)

):<>[r:int](FACT(n,r)|intr)=

(

//

if

n=0

then(FACTbas()|1)

elselet

val(pf1|r1)=ifact(n-1)//pf1:FACT(n-1,r1)

val(pfmul|r)=imul2(n,r1)//pfmul:FACT(n,r1,r)

in

(FACTind(pf1,pfmul)|r)

end//endof[else]

//

)(*endof[ifact]*)

//

Afterprooferasure, ifact preciselyimplementsthefactorialfunction.

Pleasefindtheentiretyoftheabovepresentedcodeplussometestingcodeon-line.

Page 240: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:AnotherVerifiedFactorial

The function ifact presented in the section on specifying with enhanced precision is a verifiedimplementationofthefactorialfunctionasitstypeguaranteesthat ifact implementsthespecificationoffactorialencodedbythedataprop FACT .Clearly,theimplementationof ifact closelyfollowsthedeclaration of FACT . If we think of the latter as a logic program, then the former is essentially afunctionalversionextractedfromthelogicprogram.However,theimplementationofaspecificationinpracticecanoftendigressfarfromthespecificationalgorithmically.Forinstance,wemaywanttohaveaverifiedimplementationoffactorialthatisalsotail-recursive.Thiscanbedoneasfollows:

fun

ifact2

{n:nat}.<>.

(

n:int(n)

):<>[r:int](FACT(n,r)|intr)=let

funloop

{i:nat|i<=n}{r:int}.<n-i>.

(

pf:FACT(i,r)

|n:intn,i:inti,r:intr

):<>[r:int](FACT(n,r)|intr)=

ifn-i>0thenlet

val(pfmul|r1)=imul2(i+1,r)inloop(FACTind(pf,pfmul)|n,i+1,r1)

endelse(pf|r)//endof[if]

//endof[loop]

in

loop(FACTbas()|n,0,1)

end//endof[ifact2]

Thefunction ifact2 isassignedatypeindicatingthat ifact2 isaverifiedimplementationoffactorial,anditisdefinedasacalltotheinnerfunction loop thatisclearlytail-recursive.Ifweerasetypesandproofs,thefunction ifact2 isessentiallydefinedasfollows:

funifact2(n)=let

funloop(n,i,r)=

ifn-i>0thenlet

valr1=(i+1)*rinloop(n,i+1,r1)

endelser//endof[if]

//endof[loop]

in

loop(n,0,1)

end//endof[ifact2]

Page 241: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Whentheinnerfunction loop iscalledonthreeargumentsn,iandr,thepreconditionforthiscallisthati isnaturalnumberlessthanorequaltonandrequalsfact(i), thatis, thevalueofthefactorialfunctiononi.Thispreconditioniscapturedbythetypeassignedto loop andthusenforcedateachcallsiteof loop intheimplementationof ifact2 .

Pleasefindon-linetheentiretyoftheabovepresentedcodeplussometestingcode.

Page 242: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:VerifiedFastExponentiation

Givenanintegerx,pow(x,n),thenthpowerofx,canbedefinedinductivelyasfollows:

pow(x,0)=1

pow(x,n)=x*pow(x,n-1)(foralln>0)

Adirectimplementationofthisdefinitionisgivenasfollows:

funipow{n:nat}.<n>.

(x:int,n:intn):int=ifn>0thenx*ipow(x,n-1)else1

//endof[ipow]

whichisoftime-complexityO(n)(assumingmultiplicationisO(1)).Amoreefficientimplmentationcanbegivenasfollows:

fun

ifastpow

{n:nat}.<n>.

(

x:int,n:intn

):int=

ifn>0thenlet

valn2=half(n)

vali2=n-(2*n2)

in

ifi2>0thenifastpow(x*x,n2)elsex*ifastpow(x*x,n2)

endelse1//endof[if]

//endof[ifastpow]

whichmakesuseofthepropertythatpow(x,n)equalspow(x*x,n/2)ifnisevenorx*pow(x*x,n/2)if n is odd. This is referred to as fast exponentiation. Note that ifastpow is of time-complexityO(log(n)).

Clearly,whatisdoneaboveisnotrestrictedtoexponentiationonintegers.Aslongastheunderlyingmultiplication is associative, fast exponentiationcanbeemployed tocomputepowersof anygivenelement. In particular, powers of square matrices can be computed in this way. I now present asfollowsaverifiedgenericimplementationoffastexponentiation.

HandlinggenericdataproperlyinaverifiedimplementationoftenrequiressomefinessewiththetypesystemofATS.Letusfirstintroduceanabstracttypeconstructor ELT asfollows:

Page 243: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

sortdefelt=int//[elt]isjustanaliasfor[int]

abst@ypeELT(a:t@ype,x:elt)=a//[x]isanimaginarystamp

Thisisoftenreferredtoasstamping.ForeachtypeTandstampx, ELT(T,x) isjustTasfarasdatarepresentation isconcerned.Thestampsare imaginaryand theyare solelyused for thepurposeofspecification.Letusnextintroduceanabstractprop-type MUL andafunctiontemplate mul_elt_elt :

//

abspropMUL(elt,elt,elt)//abstractmulrelation

//

fun

{a:t@ype}

mul_elt_elt{x,y:elt}

(x:ELT(a,x),y:ELT(a,y)):[xy:elt](MUL(x,y,xy)|ELT(a,xy))

//endof[mul_elt_elt]

//

Pleasedonotconfuse MUL withtheoneofthesamenamethatisdeclaredinarith_prf.sats.Tostatethattheencodedmultiplicationisassociative,wecanintroducethefollowingprooffunction:

praxi

mul_assoc

{x,y,z:elt}{xy,yz:elt}{xy_z,x_yz:elt}

(

MUL(x,y,xy),MUL(xy,z,xy_z),MUL(y,z,yz),MUL(x,yz,x_yz)

):[xy_z==x_yz]void//endof[mul_assoc]

Thekeyword praxi indicatesthat mul_assoc istreatedasaformofaxiom,whichisnotexpectedtobeimplemented.

Theabstractpowerfunctioncanbereadilyspecifiedintermsoftheabstractprop-type MUL :

dataprop

POW(

elt(*base*),int(*exp*),elt(*res*)

)=//res=base^exp

|{x:elt}

POWbas(x,0,1(*unit*))

|{x:elt}{n:nat}{p,p1:elt}

POWind(x,n+1,p1)of(POW(x,n,p),MUL(x,p,p1))

//endof[POW]

Ascanbeexpected,genericfastexponentiationisgiventhefollowinginterface:

Page 244: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

fun{a:t@ype}

fastpow_elt_int{x:elt}{n:nat}

(x:ELT(a,x),n:intn):[p:elt](POW(x,n,p)|ELT(a,p))

//endof[fastpow_elt_int]

With thepreparationdone above, a straightforward implementationof fastpow_elt_int can nowbepresentedasfollows:

implement

{a}(*tmp*)

fastpow_elt_int

(x,n)=let

//

(*

lemma:(x*x)^n=x^(2n)

*)

extern

prfun

lemma

{x:elt}{xx:elt}{n:nat}{y:elt}

(pfxx:MUL(x,x,xx),pfpow:POW(xx,n,y)):POW(x,2*n,y)

//

overload*withmul_elt_elt//[*]loadedwithmul_elt_elt

//

in

//

if

n=0

thenlet

valres=mulunit<a>()in(POWbas()|res)//res=1

end//endof[then]

elselet

valn2=halfn

val(pfxx|xx)=x*x

val(pfpow2|res)=fastpow_elt_int<a>(xx,n2)//xx^n2=res

prvalpfpow=lemma(pfxx,pfpow2)//pfpow:x^(2*n2)=res

in

ifn=2*n2

then(pfpow|res)

elselet

val(pfmul|xres)=x*resin(POWind(pfpow,pfmul)|xres)

end//endof[else]

end//endof[else]

//

end//endof[fastpow_elt_int]

Page 245: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Notethatthisimplementationof fastpow_elt_int isnottail-recursive.Thefunctiontemplate mulunit ,which is called to produce a unit for the underlying multiplication, is assigned the followinginterface:

fun{a:t@ype}mulunit():ELT(a,1(*stamp*))

Theprooffunction lemma simplyestablishesthatpow(x,2*n)=pow(x*x,n)foreachnaturalnumbern.Ihavemadeanimplementationof lemma availableon-linebut Isuggest that the interestedreadergiveitatryfirsttoimplement lemma beforetakingalookatthegivenimplementation.Notethatthefollowingaxiomsareneededtoimplement lemma :

//

praxi

mul_istot//MUListotal

{x,y:elt}((*void*)):[xy:elt]MUL(x,y,xy)

//

praxi

mul_isfun//MULisfunctional

{x,y:elt}{z1,z2:elt}(MUL(x,y,z1),MUL(x,y,z2)):[z1==z2]void

//

Anotherinteresting(andpossiblyabitchallenging)exerciseistoimplement fastpow_elt_int inatail-recursivefashion.

Please findon-line the two files fastexp.satsandfastexp.dats that contain the entirety of the abovepresentedcode.

Nowwehave implemented fastpow_elt_int .Howcan itbeused?Pleasefindon-line anexample inwhich fastpow_elt_int is called to implement fast exponentiation on a 2-by-2 matrix so that theFibonaccinumberscanbecomputedinahighlyefficientmanner.

Page 246: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

IV.ProgrammingwithViewsandViewtypesTableofContents13.IntroductiontoViewsandViewtypes14.DataviewsasLinearDataprops15.DataviewtypesasLinearDatatypes16.AbstractViewsandViewtypes

Page 247: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 248: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 249: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter 13. Introduction to Views andViewtypesProbablythesinglegreatestmotivationbehindthedevelopmentofATSisthedesiretomakeATSaprogramming language that can be employed effectively to construct safe and reliable programsrunninginthekernelsofoperatingsystems.Insteadoffollowingseeminglynaturalapproachesthatoftenfocusoncarvingouta"safe"subsetofCand/orputwrappersaround"unsafe"programmingfeatures in C, ATS relies on the paradigm of programming with theorem-proving to preventresourcessuchasmemoryfrombeingmisusedormismanaged,advocatinganapproachtosafetythatis both general and flexible. For example, awell-typed program constructed inATS cannot causebuffer overrun at run-time even though pointer arithmetic is fully supported in ATS. Morespecifically, if a pointer is to be dereferenced,ATS requires that a proof be given attesting to thesafetyofthedereferencingoperation.Proofsofthiskindareconstructedtodemonstratethevalidityof linearpropositions,whichare referred toasviews inATS, forclassifying resourcesaswell ascapabilities.

Pleasefindon-linethecodepresentedforillustrationinthischapter.

Page 250: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ViewsforMemoryAccessthroughPointers

Aviewisalinearversionofprop,wherethewordlinearcomesfromlinearlogic,aresource-awarelogicinventedbyJean-YvesGirard.Thereisabuilt-insort view forstatictermsrepresentingviews.GivenatypeTandamemorylocationL,aviewoftheform T@L canbeformedtoindicateavalueofthetypeTbeingstoredinthememoryatthelocationL,where @ isaspecialinfixoperator.Viewsofthis form are extremely common in practice, and they are often referred to as at-views. As anexample,thefollowingfunctiontemplates ptr_get0 and ptr_set0 ,whichreadsandwrites throughagivenpointer,areassignedtypescontainingat-views:

fun{a:t@ype}

ptr_get0{l:addr}(pf:a@l|p:ptrl):(a@l|a)

fun{a:t@ype}

ptr_set0{l:addr}(pf:a?@l|p:ptrl,x:a):(a@l|void)

Notethat ptr isatypeconstructorthatformsatype ptr(L) whenappliedtoastatictermLofthesortaddr ,andtheonlyvalueofthetype ptr(L) isthepointerthatpointstothelocationdenotedbyL.

GivenatypeT,thefunction ptr_get0<T> isassignedthefollowingtype:

{l:addr}(T@l|ptr(l))->(T@l|T)

whichindicatesthatthefunction ptr_get0<T> returnsaproofoftheview T@L andavalueofthetypeTwhen applied to a proof of the view T@L and a pointer of the type ptr(L) for some L. Intuitivelyspeaking,aproofoftheview T@L ,whichisaformofresourceas T@L islinear,isconsumedwhenitis passed to ptr_get0<T> , and another proof of the same view T@L is generated when ptr_get0<T>

returns.Noticethataproofoftheview T@L mustbereturnedforotherwisesubsequentaccessestothememorylocationLwouldhavebeenprecluded.

Similarly,thefunction ptr_set0<T> isassignedthefollowingtype:

{l:addr}(T?@l|ptr(l))->(T@l|void)

NotethatT?isatypeforvaluesofsize sizeof(T) thatareassumedtobeuninitialized.Thefunctionptr_set0<T> returnsaproofoftheview T@L whenappliedtoaproofoftheview T?@L ,apointerofthetype ptr(L) andavalueofthetypeT.Theuseoftheview T?@L indicatesthatthememorylocationatLisassumedtobeuninitializedwhen ptr_set0<T> iscalled.

Page 251: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Asanexample,afunctiontemplate swap0 isimplementedasfollowsforswappingmemorycontentsattwogivenlocations:

fn{a:t@ype}

swap0{l1,l2:addr}

(

pf1:a@l1,pf2:a@l2

|p1:ptr(l1),p2:ptr(l2)

):(a@l1,a@l2|void)=let

val(pf1|x1)=ptr_get0<a>(pf1|p1)

val(pf2|x2)=ptr_get0<a>(pf2|p2)

val(pf1|())=ptr_set0<a>(pf1|p1,x2)

val(pf2|())=ptr_set0<a>(pf2|p2,x1)

in

(pf1,pf2|())

end//endof[swap0]

Compared to a corresponding implementation inC, theverbosityof this one inATS is evident. Inparticular,theneedforthreadinglinearproofsthroughcallstofunctionsthatmakeuseofresourcescanoften result in a lotofadministrative code tobewritten. I nowpresent some special syntax tosignificantlyalleviatetheneedforsuchadministrativecode.

Thefunctiontemplates ptr_get1 and ptr_set1 aregiventhefollowinginterfaces:

fun{a:t@ype}

ptr_get1{l:addr}(pf:!a@l>>a@l|p:ptrl):a

fun{a:t@ype}

ptr_set1{l:addr}(pf:!a?@l>>a@l|p:ptrl,x:a):void

Clearly,foreachtypeT,thefunction ptr_get1<T> isassignedthefollowingtype:

{l:addr}(!T@l>>T@l|ptr(l))->T

Givenalinearproofpfoftheview T@L forsomeLandapointerpofthetype ptr(L) ,thefunctioncall ptr_get1<T> (pf, p) is expected to return a value of the type T. However, the proof pf is notconsumed. Instead, it is still a proof of the view T@L after the function call returns. Similarly, thefunction ptr_set1<T> isassignedthefollowingtype:

{l:addr}(!T?@l>>T@l|ptr(l),T)->void

Givenalinearproofpfoftheview T?@L forsomeL,apointerpofthetype ptr(L) andavaluevof

Page 252: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

thetypeT,thefunctioncall ptr_set1<T> (pf,p,v)isexpectedtoreturnthevoidvaluewhilechangingtheviewofpffrom T?@L to T@L .Ingeneral,assumethatfisgivenatypeofthefollowingformforsomeviewsV1andV2:

(...,!V1>>V2,...)->...

Thenafunctioncallf(...,pf,...)onsomeproofvariablepfoftheviewV1istochangetheviewofpfintoV2uponitsreturn.InthecasewhereV1andV2arethesame,!V1>>V2cansimplybewrittenas!V1. As an example, a function template swap1 for swapping the contents at two given memorylocationsisimplementedasfollows:

fn{a:t@ype}

swap1{l1,l2:addr}(

pf1:!a@l1,pf2:!a@l2|p1:ptrl1,p2:ptrl2

):void=let

valx=ptr_get1<a>(pf1|p1)

val()=ptr_set1<a>(pf1|p1,ptr_get1<a>(pf2|p2))

val()=ptr_set1<a>(pf2|p2,x)

in

//nothing

end//endof[swap1]

Clearly,thisimplementationisconsiderablycleanerwhencomparedtotheaboveimplementationofswap0 .

Afurthersimpliedimplementationof swap1 isgivenasfollows:

fn{a:t@ype}

swap1{l1,l2:addr}

(

pf1:!a@l1,pf2:!a@l2

|p1:ptr(l1),p2:ptr(l2)

):void=let

valtmp=!p1in!p1:=!p2;!p2:=tmp

end//endof[swap1]

Givenapointerpofthetype ptr(L) forsomeL, !p yieldsthevaluestoredatthememorylocationL.The typechecker first searches for a proof of the view T@L for some T among all the currentlyavailableproofswhentypechecking !p ;ifsuchaproofpfisfound,then !p isessentiallyelaboratedinto ptr_get1(pf | p) and then typechecked.As !p isa left-value (which is tobeexplained later indetail), it canalsobeused to formanassignment like !p := v for somevaluev.The typechecker

Page 253: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

elaborates !p:=v into ptr_set1(pf|p,v) forthesakeoftypecheckingifaproofoftheat-view T@LcanbefoundforsometypeTamongallthecurrentlyavailableproofs.Notethatthisimplementationof swap1 makesnouseofadministrativecodeforhandlinglinearproofsexplicitly.

Page 254: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ViewtypesasaCombinationofViewsandTypes

AlineartypeinATSisgiventhenameviewtype,whichischosentoindicatethatalineartypeconsistsoftwoparts:onepartforviewsandtheotherfor types.Forinstance,givenaviewVandatypeT,then the tuple (V |T) is aviewtype,where thebar symbol (|) is a separator (just likeacomma) toseparateviews from types.What seemsabit surprising is theopposite:For eachviewtypeVT,wemayassumetheexistenceofaviewVandatypeTsuchthatVTisequivalentto(V|T).Formally,thisT can be referred as VT?! in ATS. This somewhat unexpected interpretation of linear types is astrikingnoveltyofATS,whichstressesthatthelinearityofaviewtypecomesentirelyfromtheviewpartresidingwithinit.

Thebuilt-insorts viewtype and viewt@ype areforstatictermsrepresentingviewtypeswhosetypepartsareofthesorts type and t@ype ,respectively.Inotherwords,theformerisassignedtoviewtypesforlinear values of the size equal to that of a pointer and the latter to viewtypes for linear values ofunspecifiedsize.Forexample, tptr isdefinedasfollowsthattakesatypeandanaddresstoformaviewtype(ofthesort viewtype ):

vtypedeftptr(a:t@ype,l:addr)=(a@l|ptrl)

GivenatypeTandanaddressL, theviewtype tptr(T,L) is forapointer toLpairedwitha linearproofstatingthatavalueofthetypeTisstoredatL.Ifwethinkofacounterasapointerpairedwithaproofstatingthatthepointerpointstoaninteger(representingthecount),thenthefollowingdefinedfunction getinc returnsthecurrentcountofagivencounterafterincreasingitby1:

fngetinc

{l:addr}{n:nat}

(

cnt:!tptr(int(n),l)>>tptr(int(n+1),l)

):int(n)=nwhere{

valn=ptr_get1<int(n)>(cnt.0|cnt.1)

val()=ptr_set1<int(n+1)>(cnt.0|cnt.1,n+1)

}(*endof[getinc]*)

Aparticularlyinterestingexampleofaviewtypeisthefollowingone:

vtypedefcloptr

(a:t@ype,b:t@ype,l:addr)=

[env:t@ype](((&env,a)->b,env)@l|ptrl)

//endof[cloptr_app]

Page 255: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

GiventwotypesAandB,apointertosomeaddressLwhereaclosurefunctionisstoredthattakesavalueofthetypeAtoreturnavalueofthetypeBcanbegiventheviewtype cloptr(A,B,L) .Notethata closure function is just an envless function pairedwith an environment containing bindings forvariables in thebodyof the closure function that are introduced fromoutside. In the function type(&env, a) -> b , the symbol & indicates that the corresponding function argument is passed byreference,thatis,theargumentisrequiredtobealeft-valueandwhatisactuallypassedatrun-timeistheaddressoftheleft-value.Iwillcovertheissueofcall-by-referenceelsewhereinmoredetails.Thefollowing piece of code demonstrates a pointer to a closure function being called on a givenargument:

fun{

a:t@ype}{b:t@ype

}cloptr_app{l:addr}

(

pclo:!cloptr(a,b,l),x:a

):b=let

valp=pclo.1

(*

//

//takingoutpf:((&env,a)->b,env)@l

//

prvalpf=pclo.0

//

*)

valres=!p.0(!p.1,x)

(*

prval()=pclo.0:=pf//puttingtheproofpfback

*)

in

res

end//endof[cloptr]

Notethatthelinearproofin pclo isfirsttakenoutsothatthecodefordereferencingp(denotedbythesyntax !p )canpasstypechecking,anditisthenreturnedsothatthetypeof pclo isrestoredtoitsoriginalone.ThisprocessoftakingoutalinearprooffromarecordandthenputtingitbackintotherecordcanbeautomaticallyperformedbythetypecheckerofATS.

The very ability to explain within ATS programming features such as closure function is aconvincingindicationoftheexpressivenessofthetypesystemofATS.

Page 256: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Left-ValuesandCall-by-Reference

In its simplest form,a left-value is justapointerpairedwitha linearproofattesting toavalue (ofsometype)beingstoredatthelocationtowhichthepointerpoints.Thenameleft-value stemsfromsuchavaluebeingallowedtoappearontheleft-handsideofanassignmentstatement(inlanguageslikeC).Often,aleft-valueisintuitivelyexplainedasavaluewithanaddressattachedtoit.Notethatwhateverrepresentationchosenforaleft-valuemustmakeitpossibletoidentifyboththepointerandthelinearproof(ofsomeat-view)thatareassociatedwiththeleft-value.

InATS,thesimplestexpressionrepresentingaleft-valueis !p ,where ! isaspecialsymbolandpavalueofthetype ptr(L) forsomeaddressL.Whenthisexpressionistypechecked,aproofof T@L forsometypeTisrequiredtobefoundamongthecurrentlyavailableproofs.Iwillintroduceadditionalformsofleftvaluesgradually.

The default strategy for passing a function argument in ATS is call-by-value. However, it is alsoallowedinATStospecifythatcall-by-referenceischosenforpassingaparticularfunctionargument.By call-by-reference, it is meant that the argument to be passed must be a left-value and what isactually passed is the address of the left-value (instead of the value stored at the address). Forexample,thefollowingdefinedfunction swap2 makesessentialuseofcall-by-reference:

fn{

a:t@ype

}swap2(

x1:&a,x2:&a

):void=let

valtmp=x1inx1:=x2;x2:=tmp

end//endof[swap2]

Notethatthespecialsymbol & infrontofthetypeofafunctionargumentindicatesthattheargumentneedstobepassedaccordingtothecall-by-referencestrategy.Thefollowingcodeimplements swap1basedon swap2 :

fn{

a:t@ype

}swap1{l1,l2:addr}

(

pf1:!a@l1,pf2:!a@l2|p1:ptrl1,p2:ptrl2

):void=swap2(!p1,!p2)

Whenthecall swap2(!p1,!p2) isevaluatedatrun-time, theparametersactuallybeingpassedare the

Page 257: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

twopointers p1 and p2 (rather than the values stored at the locations towhich these twopointerspoint).

GivenatypeTandanintegerN,thesyntax @[T][N] standsforaflatarrayconsistingNelementsofthetypeT.Pleasenotethatavalueofthetype @[T][N] isofthesizeN*sizeof(T).Ifafunctionhasaparameterrepresentinganarray, then thisparameter ismost liklelycall-by-reference.For instance,the following code implements a function that takes two arrays of doubles to compute their dotproduct(alsoknownsasinnerproduct):

fundotprod

(

A:&(@[double][3])

,B:&(@[double][3])

):double=

(

A[0]*B[0]+A[1]*B[1]+A[2]*B[2]

)

Notethatbotharrayargumentsof dotprod arecall-by-reference.

Page 258: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Stack-AllocatedVariables

Givena typeTandan addressL,howcanaproofof theview T@L be obtained in the first place?Thereareactuallyavarietyofmethods forobtainingsuchproofs inpractice,and Ipresentoneasfollowsthatisbasedonstack-allocationoflocalvariables.

Inthebodyofthefollowingfunction foo ,somestack-allocatedlocalvariablesaredeclared:

fnfoo():void=let

varx0:int//view@(x0):int?@x0

val()=x0:=0//view@(x0):int(0)@x0

varx1:int=1//view@(x1):int(1)@x1

//

//[with]isakeywordinATS

//

vary:intwithpfy//pfyisanaliasofview@(y):int?@y

val()=y:=2//pfy=view@(y):int(2)@y

varz:intwithpfz=3//pfzisanaliasofview@(z):int(3)@z

in

//nothing

end//endof[foo]

Thekeyword var isfordeclaringalocalvariable.Whenavariableisdeclared,eitheritstypeoritsinitialvalueneedstobegiven.Ifavariableisdeclaredwithoutatype,thenthetypeofitsinitialvalueis assumed to be its type. Assume that a variable x is declared of type T. Then the pointer to thelocationofthevariableisdenotedby addr@(x) ,where addr@ isakeyword,anditsassociatedlinearproof (of some at-view) can be referred to as view@(x) , where view@ is a keyword. A variable isanotherformofleft-valueinATS.Inthebodyof foo , x0 isdeclaredtobeavariableofthetype intandthenitisinitializedwiththeinteger0; x1 isdeclaredtobeavariableofthetype int thatisgiventheinitialvalue1; y isdeclaredtobeavariableofthetype int while pfy isintroducedasanaliasfor view@(y) ,andthen y isinitializedwiththeinteger2; z isdeclaredtobeavariableofthetype intthatisgiventheinitialvalue3while pfz isintroducedasanaliasfor view@(z) .

Thefollowingcodegivesanimplementationofthefactorialfunction:

fnfact{n:nat}

(n:int(n)):int=let

funloop{n:nat}{l:addr}.<n>.

(pf:!int@l|n:intn,res:ptrl):void=

ifn>0thenlet

val()=!res:=n*!resinloop(pf|n-1,res)

Page 259: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

end//endof[if]

//endof[loop]

varres:intwithpf=1

val()=loop(pf|n,addr@res)//addr@res:thepointertores

in

res

end//endof[fact]

Notethat thevariable res holds the intermediate resultduring theexecutionof the loop.As res isstack-allocated, there is no garbage generated after a call to fact is evaluated.When this style ofprogrammingisdoneinC,thereisoftenaconcernaboutthepointerto res beingderefencedafteracallto fact returns,whichiscommonlyreferredtoasderefencingadanglingpointer.ThisconcerniscompletelyeliminatedinATSasitisrequiredbythetypesystemofATSthatalinearproofoftheat-view associated with the variable res be present at the end of legal scope for res . Morespecifically,ifxisadeclaredvariableofthetypeT,thenalinearproofoftheview T?@L ,whereListhe address of x, must be available when typechecking reaches the end of the scope for x. Thisrequirementensuresthatavariablecannolongerbeaccessedaftertheportionofthestackinwhichitis allocated is reclaimed as no linear proof of the at-view associated with the variable is everavailablefromthatpointon.

ArraysinATScanalsobestack-allocated.Forinstance, thefollowingcodeallocatestwoarraysofdoubles in the frame of the function main0 and then passes them to dotprod to compute their dotproduct:

implement

main0()=

{

//

varA=@[double][3](1.0)//initializedwith1.0,1.0,1.0

varB=@[double](1.0,2.0,3.0)//initializedwith1.0,2.0,3.0

//

val()=println!("A*B=",dotprod(A,B))//A*B=6.0

//

}(*endof[main0]*)

Theat-viewassociatedwiththevariableAis (@[double][3])@A ,whereAalsoreferstotheaddressofthevariableA.Similarly,theat-viewassociatedwiththevariableBis (@[double][3])@B .Forthesakeof completeness, I mention the syntax for uninitialized arrays as follows: Given a type T and anintegerN,thesyntax @[T][N]() isforanarrayconsistingofNuninitializedvaluesoftypeT.

Page 260: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Notethatallocatinglargearraysinthecallframeofafunctionmaynotbeagoodpracticeasdoingsocangreatlyincreasethelikelihoodofstack-overflowatrun-time.

It is also allowed in ATS to allocate a closure in the call frame of a function. For instance, thefollowing code implements a function named foo that stores a flat closure-function in a stack-allocatedvariablenamed bar :

funfoo

(

x:int,y:int

):int=let

//

varbar=lam@():int=>x*y

//

in

bar()

end//endof[foo]

Note that thespecialkeyword lam@ shouldbeused to forma flat closure-function.For the sakeofcompleteness,Ipresentanotherexampleasfollowstoshowthatarecursiveclosure-functioncanalsobestoredinastack-allocatedvariable:

funfoo2

(

x:int,y:int

):int=let

//

varbar2=fix@f(x:int):int=>ifx>0theny+f(x-1)else0

//

in

bar2(x)

end//endof[foo]

Notethatthespecialkeyword fix@ shouldbeusedtoformaflatrecursiveclosure-function.

In a settingwhere dynamicmemory allocation is not allowed, stack-allocated closures can play apivotalroleinsupportingprogrammingwithhigher-orderfunctions.

Page 261: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Heap-AllocatedLinearClosure-Functions

InATS,aclosure-functioncanbeassigedalineartype,allowingittobeproperlytrackedwithinthetypesystemandalsoexplicitlyfreedbytheprogrammer.

Thefollowingcodeimplementsahigher-orderfunction list_map_cloptr whichtakesalinearclosure-functionasitssecondargument:

fun{

a:t@ype}{b:vt@ype

}list_map_cloptr{n:int}

(

xs:list(a,n),f:!(a)-<cloptr1>b

):list_vt(b,n)=

(

case+xsof

|list_nil()=>list_vt_nil()

|list_cons(x,xs)=>list_vt_cons(f(x),list_map_cloptr<a><b>(xs,f))

)

Note that the keyword -<cloptr1> indicates that the function type it forms is for a linear closure-function.Ifatypeforapurelinearclosure-functionisneeded,thekeyword -<cloptr0> canbeused.The symbol ! in front of the function type means that the second (linear) argument oflist_map_cloptr iscall-by-valueanditisstillavailableafter list_map_cloptr returns.

Letusnowseesomeconcretecodeinwhichalinearclosure-functioniscreated,called,andfinallyfreed:

implement

main0()=

{

//

valxs=

$list_vt{int}(0,1,2,3,4)

//

vallen=list_vt_length(xs)

//

valf=lam(x:int):int=<cloptr1>x*len

//

valys=

list_map_cloptr<int><int>($UNSAFE.list_vt2t(xs),f)

//

val()=cloptr_free($UNSAFE.castvwtp0{cloptr(void)}(f))

Page 262: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

//

val()=println!("xs=",xs)//xs=0,1,2,3,4

val()=println!("ys=",ys)//ys=0,5,10,15,20

//

val((*freed*))=list_vt_free(xs)

val((*freed*))=list_vt_free(ys)

//

}(*endof[main0]*)

Thefunction cloptr_free isgiventhefollowinginterface:

funcloptr_free{a:t0p}(pclo:cloptr(a)):<!wrt>void

Also,thecastinvolvedin $UNSAFE.castvwtp0{cloptr(void)}(f) isasafecast.

Thesupportforlinearclosure-functionsinATS1iscrucialinasettingwherehigher-orderfunctionsare needed but run-time garbage collection (GC) is not allowed or supported. In ATS2, linearclosure-functions become much less important as programming with higher-order functions in asettingwithoutGCcanbemoreconvenientlyachievedthroughtheuseoftemplates.However,ifonewantstostoreclosure-functionsinadatastructurewithoutcausingmemoryleaks,itisnecessarytouselinearclosure-functionsunlessGCcanbereliedupontoreclaimmemory.

Page 263: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 264: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 265: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter14.DataviewsasLinearDatapropsTheat-viewsoftheform T@L fortypesTandaddressesLarebuildingblocksforconstructingotherformsofviews.Onemechanismforputtingtogethersuchbuildingblocksisbydeclaringdataviews,which is mostly identical to declaring dataprops. I now present in this chapter some commonlyencountereddataviewsandtheiruses.

Pleasefindon-linethecodepresentedforillustrationinthischapter.

Page 266: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

OptionalViews

Thedataview option_v isdeclaredasfollows:

dataviewoption_v(v:view+,bool)=

|Some_v(v,true)of(v)|None_v(v,false)of()

Thisdeclarationindicates that thedataview option_v iscovariant in its firstargumentand therearetwoproofconstructorsassociatedwithit: Some_v and None_v .GivenaviewV, option_v(V,b) isoftencalledanoptionalview,wherebisaboolean.Clearly,aproofoftheview option_v(V,true) containsaproofoftheviewVwhileaprooftheview option_v(V,false) containsnothing.

Asanexample,thefollowingfunctioninterfaceinvolvesatypicaluseofoptionalview:

fun{a:t@ype}

ptr_alloc_opt():[l:addr](option_v(a?@l,l>null)|ptrl)

Given a typeT, the function ptr_alloc_opt<T> returns a pointer pairedwith a proof of an optionalview;ifthereturnedpointerisnotnull,thentheproofcanbeturnedintoaproofoftheview T?@L ,whereListhelocationtowhichthepointerpoints;otherwise,thereisnoat-viewassociatedwiththereturnedpointer.

Page 267: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

DisjunctiveViews

Thedataview VOR isdeclaredasfollows:

dataviewVOR(v0:view+,v1:view+,int)=

|VORleft(v0,v1,0)of(v0)|VORright(v0,v1,1)of(v1)

This declaration indicates that the dataview VOR is covariant in its first and second arguments andtherearetwoproofconstructorsassociatedwithit: VORleft and VORright .GivenviewsV0andV1,aproofof VOR(V0,V1,0) canbeturnedintoaproofofV0andaproofof VOR(V0,V1,1) canbeturnedintoaproofofV1.

LetTbesometype.Thefollowingfunctioninterfacestatesthat getopt takesanunintializedpointerandreturnsanintegersindicatingwhetherthepointerisinitialized:

fungetopt{l:addr}

(pf:T?@l|ptr(l)):[i:int](VOR(T?@l,T@l,i)|int(i))

Thefollowingcodeshowsatypicaluseof getopt :

funfoo():void=let

varx:T?

val(pfor|i)=getopt(view@(x)|addr@(x))

in

//

ifi=0

thenlet

prvalVORleft(pf0)=pforinview@(x):=pf0//uninitialized

end//endof[then]

elselet

prvalVORright(pf1)=pforinview@(x):=pf1//initialized

end//endof[else]

//endof[if]

//

end//endof[foo]

InATS,thereisatypeconstructor opt thattakesatypeTandabooleanBtoformanopt-type opt(T,B) suchthat opt(T,B) equalsTifBistrueanditequalsT?ifBisfalse.Thefunction getopt canbegiventhefollowinginterfacethatmakesuseofanopt-type:

fungetopt(x:&T?>>opt(T,b)):#[b:bool]bool(b)

Page 268: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Thecodethatcalls getopt cannowbeimplementedasfollows:

funfoo():void=let

varx:T?

valans=getopt(x)

in

//

if(ans)

thenlet

prval()=opt_unsome(x)in(*initialized*)

end//endof[then]

elselet

prval()=opt_unnone(x)in(*uninitialized*)

end//endof[else]

//endof[if]

//

end//endof[foo]

wheretheprooffunctions opt_unsome and opt_unnone areassginedthefollowingtypes:

prfunopt_unsome{a:t@ype}(x:!opt(a,true)>>a):void

prfunopt_unnone{a:t@ype}(x:!opt(a,false)>>a?):void

Comparedtotheversionthatuses VOR ,thisversionbasedonopt-typeisconsiderablylessverbose.

Page 269: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

DataviewforLinearArrays

Unlike in most programming languages, arrays are not a primitive data structure in ATS. Morespecifically,persistentarrayscanbeimplementedbasedonlineararrays,whichallowforbeingfreedsafelyby theprogrammer,and lineararrayscanbe implementedbasedonat-views. Intuitively, theviewforanarraystoringNelementsoftypeTconsistsofNat-views:T@L0,T@L1,...,andT@LN-1,whereL0isthestartingaddressofthearrayandeachsubsequentLequalsthepreviousoneplusthesizeofT,thatis,thenumberofbytesneededtostoreavalueofthetypeT.Thefollowingdeclareddataview array_v preciselycapturesthisintuituion:

dataview

array_v(

a:t@ype+//covariantargument

,addr(*beg*)

,int(*size*)

)=//array_v

|{l:addr}

array_v_nil(a,l,0)

|{l:addr}{n:nat}

array_v_cons(a,l,n+1)of(a@l,array_v(a,l+sizeof(a),n))

//endof[array_v]

GivenatypeT,anaddressLandanintegerN, array_v(T,L,N) isaviewforthearraystartingatLthat storesN elements of the typeT.As can be readily expected, the function templates for array-accessingandarray-updatingaregiventhefollowinginterfaces:

fun{

a:t@ype

}arrget{l:addr}{n,i:nat|i<n}

(pf:!array_v(a,l,n)|p:ptrl,i:inti):a

//endof[arrget]//endof[fun]

fun{

a:t@ype

}arrset{l:addr}{n,i:nat|i<n}

(pf:!array_v(a,l,n)|p:ptrl,i:inti,x:a):void

//endof[arrset]//endof[fun]

Beforeimplementing arrget and arrset ,Ipresentasfollowssomecodethatimplementsafunctiontemplatetoaccessthefirstelementofanonemptyarray:

fun{

Page 270: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

a:t@ype

}arrgetfst{l:addr}{n:pos}

(

pf:!array_v(a,l,n)|p:ptrl

):a=xwhere{

prvalarray_v_cons(pf1,pf2)=pf

//pf1:a@l;pf2:array_v(a,l+sizeof(a),n-1)

valx=!p

prval()=pf:=array_v_cons(pf1,pf2)

}//endof[arrgetfst]

Obviously,thefunctiontemplate arrget canbeimplementedbasedon arrgetfst :

implement

{a}(*tmp*)

arrget(pf|p,i)=

ifi>0thenlet

prvalarray_v_cons(pf1,pf2)=pf

valx=arrget(pf2|ptr_succ<a>(p),i-1)

prval()=pf:=array_v_cons(pf1,pf2)

in

x

endelse

arrgetfst(pf|p)

//endof[if]

Thisisatail-recursiveimplementationoftime-complexityO(n).However,theverypointofhavingarrays is to support O(1)-time accessing and updating operations. My initial effort spent onimplementingsuchoperationsimmediatelydawnedonmetheneedtoconstructprooffunctionsforsupportingview-changes(ofnorun-timecost).

Clearly,anarraystartingatLthatstoresNelementsoftypeTcanalsobethoughtofastwoarrays:one starting at L that stores I elements while the other starting at L+I*sizeof(T) that stores N-Ielements,whereIisannaturalnumberlessthatorequaltoN.Formally,thisstatementcanbeencodedinthetypeoftheprooffunction array_v_split :

prfun

array_v_split

{a:t@ype}

{l:addr}{n,i:nat|i<=n}

(

pfarr:array_v(a,l,n)

):(array_v(a,l,i),array_v(a,l+i*sizeof(a),n-i))

Page 271: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

The other direction of the above statement can be encoded in the type of the proof functionarray_v_unsplit :

prfun

array_v_unsplit

{a:t@ype}

{l:addr}{n1,n2:nat}

(

pf1arr:array_v(a,l,n1),pf2arr:array_v(a,l+n1*sizeof(a),n2)

):array_v(a,l,n1+n2)

With array_v_split and array_v_unsplit ,wecanreadilygive implementationsof arrget and arrsetthatareO(1)-time:

implement

{a}(*tmp*)

arrget{l}{n,i}

(pf|p,i)=xwhere{

prval(pf1,pf2)=array_v_split{a}{l}{n,i}(pf)

prvalarray_v_cons(pf21,pf22)=pf2

valx=ptr_get1<a>(pf21|ptr_add<a>(p,i))

prvalpf2=array_v_cons(pf21,pf22)

prval()=pf:=array_v_unsplit{a}{l}{i,n-i}(pf1,pf2)

}(*endof[arrget]*)

implement

{a}(*tmp*)

arrset{l}{n,i}

(pf|p,i,x)=()where{

prval(pf1,pf2)=array_v_split{a}{l}{n,i}(pf)

prvalarray_v_cons(pf21,pf22)=pf2

val()=ptr_set1<a>(pf21|ptr_add<a>(p,i),x)

prvalpf2=array_v_cons(pf21,pf22)

prval()=pf:=array_v_unsplit{a}{l}{i,n-i}(pf1,pf2)

}(*endof[arrset]*)

Ofcourse, theprooffunctions array_v_split and array_v_split arestill tobe implemented,whichIwilldowhencoveringthetopicofview-change.

GivenatypeT,anaddressLandanaturalnumberN,aproofoftheview array_v(T?,L,N) canbeobtained and released by calling the functions malloc and free , respectively, which are to beexplained in details elsewhere. I now give as follows an implemention of a function template forarrayintialization:

Page 272: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

typedefnatLt(n:int)=[i:nat|i<n]int(i)

fun{a:t@ype}

array_ptr_tabulate

{l:addr}{n:nat}

(

pf:!array_v(a?,l,n)>>array_v(a,l,n)

|p:ptr(l),n:int(n),f:natLt(n)-<cloref1>a

):void=let

funloop{l:addr}

{i:nat|i<=n}.<n-i>.

(

pf:!array_v(a?,l,n-i)>>array_v(a,l,n-i)

|p:ptrl,n:intn,f:natLt(n)-<cloref1>a,i:inti

):void=

ifi<nthenlet

prvalarray_v_cons(pf1,pf2)=pf

val()=!p:=f(i)

val()=loop(pf2|ptr_succ<a>(p),n,f,i+1)

in

pf:=array_v_cons(pf1,pf2)

endelselet

prvalarray_v_nil()=pfinpf:=array_v_nil{a}()

end//endof[if]

//endof[loop]

in

loop(pf|p,n,f,0)

end//endof[array_ptr_tabulate]

Givenanaturalnumbern,thetype natLt(n) isforallnaturalnumberslessthann.GivenatypeT,thefunction array_ptr_tabulate<T> takes a pointer to an uninitialized array, the size of the array and afunctionfthatmapseachnaturalnumberlessthanntoavalueofthetypeT,anditinitializesthearraywiththesequenceofvaluesoff(0),f(1),...,andf(n-1).Inotherwords,thearraystoresatabulationofthegivenfunctionfaftertheinitializationisover.

GivenatypeTandanintegerN,@[T][N]isabuilt-intypeinATSforNconsecutivevaluesofthetypeT.Therefore, the at-view@[T][N]@L for anygiven addressL is equivalent to the array-viewarray_v(T,L,N) .Bymakinguseofthefeatureofcall-by-reference,wecanalsoassignthefollowinginterfacestothepreviouslypresentedfunctions arrget and arrset :

fun{

a:t@ype

}arrget{n,i:nat|i<n}(A:&(@[a][n]),i:inti):a

Page 273: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

fun{

a:t@ype

}arrset{n,i:nat|i<n}(A:&(@[a][n]),i:inti,x:a):void

These interfaces aremore concise as they obviate the need tomention explicitly where the arrayargumentislocated.

Pleasefindtheentiretyoftheabovepresentedcodeon-line.

Page 274: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

DataviewforLinearStrings

Thefollowingdataview strbuf_v capturesthenotionofastringinC,whichconsisitsasequenceofnon-nullcharactersfollowedbythenullcharacter.

Page 275: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

DataviewforSingly-LinkedLists

Thefollowingdataview slseg_v capturesthenotionofasingly-linkedlistsegment:

dataview

slseg_v(

a:t@ype+//covariantargument

,addr(*beg*)

,addr(*end*)

,int(*length*)

)=//slseg_v

|{l:addr}

slseg_v_nil(a,l,l,0)of()

|{l_fst:agz}{l_nxt,l_end:addr}{n:nat}

slseg_v_cons(a,l_fst,l_end,n+1)of

((a,ptrl_nxt)@l_fst,slseg_v(a,l_nxt,l_end,n))

//endof[slseg]_v

There are twoproof constructors slseg_v_nil and slseg_v_cons associatedwith slseg_v , which areassignedthefollowingtypes:

slseg_v_nil:

{a:t@ype}{l:addr}()->slseg_v(a,l,l,0)

slseg_v_cons:

{a:t@ype}{l_fst:agz}{l_nxt,l_end:addr}{n:nat}

((a,ptrl_nxt)@l_fst,slseg_v(a,l_nxt,l_end,n))->slseg_v(a,l_fst,l_end,n+1)

Notethat agz isasubsetsortforaddressesthatarenotnull.GivenatypeT,twoaddressesL1andL2,andanaturalnumberN,theview slseg_v(T,L1,L2,N) isforasingly-linkedlistsegmentcontainingNelementsofthetypeTthatstartsatL1andfinishesatL2.InthecasewhereL2isthenullpointer,thenthelistsegmentisconsideredalistasisformallydefinedbelow:

viewdefslist_v

(a:t@ype,l:addr,n:int)=slseg_v(a,l,null,n)

//endof[slist_v]

Givena typeT,apointerpointingtoLplusaproofof theview slist_v(T, L, N) forsomenaturalnumberNisessentiallythesameasapointertoastructofthefollowingdeclaredtype slist_struct inC:

typedef

structslist{

Page 276: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Tdata;/*[T]matchesthecorrespondingtypeinATS*/

structslist*next;/*pointingtothetailofthelist*/

}slist_struct;

Letusnowseeasimpleexampleinvolvingsingly-linkedlists:

fn{a:t@ype}

slist_ptr_length

{l:addr}{n:nat}

(

pflst:!slist_v(a,l,n)|p:ptrl

):int(n)=let

funloop

{l:addr}{i,j:nat}.<i>.

(

pflst:!slist_v(a,l,i)|p:ptrl,j:int(j)

):int(i+j)=

ifp>0thenlet

prvalslseg_v_cons(pfat,pf1lst)=pflst

valres=loop(pf1lst|!p.1,j+1)//!p.1pointstothetail

prval()=pflst:=slseg_v_cons(pfat,pf1lst)

in

res

endelselet//thelengthofanulllistis0

prvalslseg_v_nil()=pflstinpflst:=slseg_v_nil();j

end(*endof[if]*)

//endof[loop]

in

loop(pflst|p,0)

end//endof[slist_ptr_length]

Thefunctiontemplate slist_ptr_length computesthelengthofagivensingly-linkedlist.Notethattheinner function loop is tail-recursive. The above implementation of slist_ptr_length essentiallycorrespondstothefollowingimplementationinC:

intslist_ptr_length(slist_struct*p){

intres=0;

while(p!=NULL){res=res+1;p=p->next;}

returnres;

}//endof[slist_ptr_length]

Asanotherexample,thefollowingfunctiontemplate slist_ptr_reverse turnsagivenlinkedlist intoitsreverse:

Page 277: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

fn{a:t@ype}

slist_ptr_reverse

{l:addr}{n:nat}

(

pflst:slist_v(a,l,n)|p:ptrl

):[l:addr](slist_v(a,l,n)|ptrl)=let

funloop

{n1,n2:nat}

{l1,l2:addr}.<n1>.(

pf1lst:slist_v(a,l1,n1)

,pf2lst:slist_v(a,l2,n2)

|p1:ptrl1,p2:ptrl2

):[l:addr](slist_v(a,l,n1+n2)|ptrl)=

ifp1>0thenlet

prvalslseg_v_cons(pf1at,pf1lst)=pf1lst

valp1_nxt=!p1.1

val()=!p1.1:=p2

in

loop(pf1lst,slseg_v_cons(pf1at,pf2lst)|p1_nxt,p1)

endelselet

prvalslseg_v_nil()=pf1lstin(pf2lst|p2)

end//endof[if]

in

loop(pflst,slseg_v_nil|p,the_null_ptr)

end//endof[slist_ptr_reverse]

By translating the tail-recursive function loop into a while-loop, we can readily turn theimplementationof slist_ptr_reverse inATSintothefollowingimplementationinC:

slist_struct*

slist_ptr_reverse(slist_struct*p)

{

slist_struct*tmp,*res=NULL;

while(p!=NULL){

tmp=p->next;p->next=res;res=p;p=tmp;

}

returnres;

}//endof[slist_ptr_reverse]

Letusseeyetanotherexample.Listconcatenationisacommonoperationonlists.Thistime,wefirstgiveanimplementationoflistconcatenationinC:

slist_struct*

slist_ptr_append

(slist_struct*p,slist_struct*q){

Page 278: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

slist_struct*p1=p;

if(p1==NULL)returnq;

while(p1->next!=NULL)p1=p1->next;p1->next=q;

returnp;

}//endof[slist_ptr_append]

Thealgorithmisstraightforward.If p isnull,then q isreturned.Otherwise,thelastnodeinthelistpointed to by p is first found and its field of the name next then replaced with q . Thisimplementationof slist_ptr_append inCcanbetranslateddirectlyintotothefollowingoneinATS:

fn{a:t@ype}

slist_ptr_append

{l1,l2:addr}{n1,n2:nat}

(

pf1lst:slist_v(a,l1,n1)

,pf2lst:slist_v(a,l2,n2)

|p1:ptrl1,p2:ptrl2

):[l:addr](slist_v(a,l,n1+n2)|ptrl)=let

funloop

{n1,n2:nat}

{l1,l2:addr|l1>null}.<n1>.(

pf1lst:slist_v(a,l1,n1)

,pf2lst:slist_v(a,l2,n2)

|p1:ptrl1,p2:ptrl2

):(slist_v(a,l1,n1+n2)|void)=let

prvalslseg_v_cons(pf1at,pf1lst)=pf1lst

valp1_nxt=!p1.1

in

ifp1_nxt>0thenlet

val(pflst|())=loop(pf1lst,pf2lst|p1_nxt,p2)

in

(slseg_v_cons(pf1at,pflst)|())

endelselet

val()=!p1.1:=p2

prvalslseg_v_nil()=pf1lst

in

(slseg_v_cons(pf1at,pf2lst)|())

end(*endof[if]*)

end//endof[loop]

in

ifp1>0thenlet

val(pflst|())=loop(pf1lst,pf2lst|p1,p2)

in

(pflst|p1)

endelselet

prvalslseg_v_nil()=pf1lstin(pf2lst|p2)

Page 279: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

end(*endof[if]*)

end//endof[slist_ptr_append]

Intheaboveexamples,itisevidentthatthecodeinATSisalotmoreverbosethanitscounterpartinC.However, the former is alsoa lotmore robust than the latter in the followingsense: If aminorchangeismadetothecodeinATS(e.g.,renamingidentifiers,reorderingfunctionarguments), it ismost likely that a type-error is tobe reportedwhen thechangedcode is typechecked.On theotherhand,thesamethingcannotbesaidaboutthecodewritteninC.Forinstance,thefollowingerroneousimplementationof slist_ptr_reverse inCiscertainlytype-correct:

/*

**Thisimplementationis*incorrect*buttype-correct:

*/

slist_struct*

slist_ptr_reverse

(slist_struct*p)

{

slist_struct*tmp,*res=NULL;

while(p!=NULL){

tmp=p->next;res=p;p->next=res;p=tmp;

}

returnres;

}//endof[slist_ptr_reverse]

Inowpointoutthatthedataview slseg_v isdeclaredhereinamannerthatdoesnotaddresstheissueofallocatingandfreeinglistnodes,anditisdonesoforthesakeofalessinvolvedpresentation.Adataviewforsingly-linkedliststhatdoeshandleallocationanddeallocationoflistnodescanalsobedeclaredinATS,butthereisreallylittleneedforitaswecandeclareadataviewtypeforsuchliststhatisfarmoreconvenienttouse.However,dataviewsarefundamentallymoregeneralandflexiblethandataviewtypes,andtherearemanycommondatastructures(e.g.doubly-linkedlists)thatcanonlybeproperlyhandledwithdataviewsinATS.

Page 280: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ProofFunctionsforView-Changes

Bythephraseview-change,Imeanapplyingafunctiontoproofsofasetofviewstoturnthemintoproofsofanothersetofviews.As this function itself isaproof function, there isno run-timecostassociatedwitheachview-change.Forinstance,aproofoftheat-viewint32@LforanyaddressLcanbeturnedintoaproofofatupleof4at-views:int8@L,int8@L+1,int8@L+2andint8@L+3,whereint32 and int8 are types for 32-bit and 8-bit integers, respectively. Often more interesting view-changesinvolverecursivelydefinedprooffunctions,andIpresentseveralofsuchcasesintherestofthissection.

When implementing an array subscripting operation of O(1)-time, we need a proof function tochange the view of one array into the views of two adjacently located arrays and another prooffunction to do precisely the opposite. Formally speaking, we need to construct the following twoprooffunctions array_v_split and array_v_unsplit :

prfun

array_v_split

{a:t@ype}

{l:addr}{n,i:nat|i<=n}

(

pfarr:array_v(a,l,n)

):(array_v(a,i,l),array_v(a,n-i,l+i*sizeof(a)))

prfun

array_v_unsplit

{a:t@ype}

{l:addr}{n1,n2:nat}

(

pf1arr:array_v(a,l,n1),pf2arr:array_v(a,l+n1*sizeof(a),n2)

):array_v(a,l,n1+n2)

Animplementationof array_v_split isgivenasfollows:

primplmnt

array_v_split

{a}{l}{n,i}(pfarr)=let

prfunsplit

{l:addr}{n,i:nat|i<=n}.<i>.

(

pfarr:array_v(a,l,n)

):(

array_v(a,l,i)

,array_v(a,l+i*sizeof(a),n-i)

Page 281: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

)=

sifi>0thenlet

prvalarray_v_cons(pf1,pf2arr)=pfarr

prval(pf1res1,pf1res2)=split{..}{n-1,i-1}(pf2arr)

in

(array_v_cons(pf1,pf1res1),pf1res2)

endelselet

prvalEQINT()=eqint_make{i,0}((*void*))

in

(array_v_nil(),pfarr)

end//endof[sif]

in

split(pfarr)

end//endof[array_v_split]

Note that the keyword primplmnt (instead of implement ) should be used for implementing prooffunctions.One can also choose to use the keyword primplement in place of primplmnt . Clearly, theproof function split directly encodes a proof based on mathematical induction. Following is animplementationof array_v_unsplit :

primplmnt

array_v_unsplit

{a}{l}{n1,n2}

(pf1arr,pf2arr)=let

prfununsplit

{l:addr}{n1,n2:nat}.<n1>.

(

pf1arr:array_v(a,l,n1)

,pf2arr:array_v(a,l+n1*sizeof(a),n2)

):array_v(a,l,n1+n2)=

sifn1>0thenlet

prval

array_v_cons(pf1,pf1arr)=pf1arr

prvalpfres=unsplit(pf1arr,pf2arr)

in

array_v_cons(pf1,pfres)

endelselet

prvalarray_v_nil()=pf1arrinpf2arr

end//endof[sif]

in

unsplit(pf1arr,pf2arr)

end//endof[array_v_unsplit]

Theprooffunction unsplit alsodirectlyencodesaproofbasedonmathematicalinduction.

Page 282: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Letusnowseeanevenmoreinterestingprooffunctionforperformingview-change.Theinterfaceoftheprooffunction array_v_takeout isgivenasfollows:

prfun

array_v_takeout

{a:t@ype}

{l:addr}{n,i:nat|i<n}

(

pfarr:array_v(a,l,n)

):(a@l+i*sizeof(a),a@l+i*sizeof(a)-<lin,prf>array_v(a,l,n))

Notethatthefollowingtypeisforalinearprooffunctionthattakesaproofofanat-viewtoreturnaproofofanarray-view:

a@l+i*sizeof(a)-<lin,prf>array_v(a,l,n)

As such a function essentially represents an array with onemissing cell, wemay simply say thatarray_v_takeout turnstheviewofanarrayintoanat-view(foronecell)andaviewfortherestofthearray.Bymakinguseof array_v_takeout ,wecangiveanotherimplementationof arrget :

implement

{a}(*tmp*)

arrget{l}{n,i}

(pf|p,i)=xwhere{

prval(pf1,fpf2)=

array_v_takeout{a}{l}{n,i}(pf)

valx=ptr_get1<a>(pf1|ptr_add<a>(p,i))

prval()=pf:=fpf2(pf1)//puttingthecellandtheresttogether

}(*endof[arrget]*)

Theprooffunction array_v_takeout canbeimplementedasfollows:

primplmnt

array_v_takeout

{a}{l}{n,i}(pfarr)=let

prfuntakeout

{l:addr}{n,i:nat|i<n}.<i>.

(

pfarr:array_v(a,l,n)

):(

a@l+i*sizeof(a)

,a@l+i*sizeof(a)-<lin,prf>array_v(a,l,n)

)=let

prvalarray_v_cons(pf1at,pf1arr)=pfarr

Page 283: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

in

sifi>0thenlet

prval(pfres,fpfres)=takeout{..}{n-1,i-1}(pf1arr)

in

(pfres,llam(pfres)=>array_v_cons(pf1at,fpfres(pfres)))

endelselet

prvalEQINT()=eqint_make{i,0}((*void*))

in

(pf1at,llam(pf1at)=>array_v_cons(pf1at,pf1arr))

end//endof[sif]

end//endof[takeout]

in

takeout{l}{n,i}(pfarr)

end//endof[array_v_takeout]

Note that llam is a keyword for forming linear functons. Once a linear function is applied, it isconsumedandtheresourceinit,ifnotreclaimed,movesintotheresultitreturns.

The proof functions presented so far for view-changes are all manipulating array-views. Thefollowingoneisdifferentinthisregardasitcombinestwoviewsforsingly-linkedlistsegmentsintoone:

prfun

slseg_v_unsplit

{a:t@ype}

{l1,l2,l3:addr}{n1,n2:nat}

(

pf1lst:slseg_v(a,l1,l2,n1),pf2lst:slseg_v(a,l2,l3,n2)

):slseg_v(a,l1,l3,n1+n2)

Thetypeof slseg_v_unsplit essentiallystatesthatalistsegmentfromL1toL2thatisoflengthN1andanotherlistsegmentfromL2toL3thatisoflengthN2canbethoughtofasalistsegmentfromL1toL3 that isof lengthN1+N2.Thefollowing implementationof slseg_v_unsplit is largelyparallel tothatof array_v_unsplit :

primplmnt

slseg_v_unsplit

{a}(pf1lst,pf2lst)=let

prfununsplit

{l1,l2,l3:addr}{n1,n2:nat}.<n1>.

(

pf1lst:slseg_v(a,l1,l2,n1),pf2lst:slseg_v(a,l2,l3,n2)

):slseg_v(a,l1,l3,n1+n2)=

sifn1>0thenlet

Page 284: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

prvalslseg_v_cons(pf1at,pf1lst)=pf1lst

in

slseg_v_cons(pf1at,unsplit(pf1lst,pf2lst))

endelselet

prvalslseg_v_nil()=pf1lstinpf2lst

end//endof[sif]

in

unsplit(pf1lst,pf2lst)

end//endof[slseg_v_unsplit]

Thereadermayfind it interesting togivean implementationof slist_ptr_append bymakinguseofslseg_v_unsplit .

Please find on-line the files array.dats and slist.dats, which contains the code employed forillustrationinthissection.

Page 285: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 286: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 287: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter15.DataviewtypesasLinearDatatypesAdataviewtypecanbethoughtofasalinearversionofdatatype.Toalargeextent,itisacombinationof a datatype and a dataview. This programming feature is primarily introduced intoATS for thepurposeofprovidinginthesettingofmanualmemorymanagementthekindofconveniencebroughtby pattern matching. In a situation where GC must be reduced or even completely eliminated,dataviewtypescanoftenbechosenasareplacementfordatatypes.Inowpresentinthischaptersomecommonlyencountereddataviewtypesandtheiruses.

Page 288: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

LinearOptionalValues

Whenanoptionalvalueiscreated,thevalueismostlikelytobeusedimmediatelyandthendiscarded.Ifsuchavalueisassigneda linear type, thenthememoryallocatedforstoringitcanbeefficientlyreclaimed.Thedataviewtype option_vt forlinearoptionalvaluesisdeclaredasfollows:

datavtype

option_vt(a:t@ype+,bool)=

|Some_vt(a,true)ofa|None_vt(a,false)of()

//endof[option_vt]

vtypedefOption_vt(a:t@ype)=[b:bool]option_vt(a,b)

Notethat datavtype isjusttheshortversionof dataviewtype .Theintroduceddataviewtype option_vt iscovariantinitsfirstargumentandtherearetwodataconstructors Some_vt and None_vt associatedwithit.Inthefollowingexample, find_rightmost triestofindtherightmostelementinalistthatsatisfiesagivenpredicate:

fun{a:t@ype}

find_rightmost

{n:nat}.<n>.

(

xs:list(a,n),P:(a)-<cloref1>bool

):Option_vt(a)=

(

case+xsof

|list_cons(x,xs)=>let

valopt=find_rightmost(xs,P)

in

caseoptof

|~None_vt()=>ifP(x)thenSome_vt(x)elseNone_vt()

|_(*Some_vt*)=>opt

end//endof[list_cons]

|list_nil()=>None_vt()

)(*endof[find_rightmost]*)

Notethatthetildesymbol( ~ )infrontofthepattern None_vt() indicatesthatthememoryforthenodethatmatchesthepatternisfreedbefore thebodyof thematchedclauseisevaluated.In thiscase,nomemory is actually freed as None_vt ismapped to the null pointer. Iwill soon givemore detailedexplanationaboutfreeingmemoryallocatedforconstructorsassociatedwithdataviewtypes.

Asanotherexample,thefollowingfunctiontemplate list_optcons triestoconstructanewlistwithits

Page 289: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

headelementextractedfromagivenoptionalvalue:

fn{a:t@ype}

list_optcons

{b:bool}{n:nat}

(

opt:option_vt(a,b),xs:list(a,n)

):list(a,n+bool2int(b))=

case+optof

|~Some_vt(x)=>list_cons(x,xs)|~None_vt()=>xs

//endof[list_optcons]

Thesymbol bool2int standsforabuilt-instaticfunctioninATSthatmaps true and false to1and0,respectively. What is special here is that the first argument of list_optcons , which is linear, isconsumedafteracallto list_optcons returnsandthememoryitoccupiesisreclaimed.

Page 290: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

LinearLists

Alinearlistisessentiallythesameasasingly-linkedlistdepictedbythedataview slist_v .However,memoryallocationanddeallocationoflist-nodesnothandledpreviouslyarehandledthistime.Thefollowing declaration introduces a linear datatype list_vt ,which forms a boxed type (of the sortviewtype )whenappliedtoatypeandaninteger:

datavtype

list_vt(a:t@ype+,int)=

|list_vt_nil(a,0)of()

|{n:nat}

list_vt_cons(a,n+1)of(a,list_vt(a,n))

//endof[list_vt]

GivenatypeTandanintegerI, list_vt(T,I) isforlinearlistsoflengthIinwhicheachelementisofthetypeT.

Assume that a data constructor named foo is associated with a dataviewtype. Then there is acorresponding viewtype construtor of the name foo_unfold that takes n+1 addresses to form aviewtype,wherenisthearityoffoo.Forinstance,thereisaviewtypeconstructor list_vt_cons_unfoldthattakes3addressL0,L1andL2toformaviewtype list_vt_cons_unfold(L0,L1,L2) .Thisviewtypeis for a list-node created by a call to list_vt_cons such that the node is located at L0 and the twoargumentsof list_vt_cons arelocatedatL1andL2whiletheproofsfortheat-viewsassociatedwithL1andL2areputinthestoreforcurrentlyavailableproofs.

Thefollowingfunctiontemplate length computesthelengthofagivenlinearlist:

fn{

a:t@ype

}length{n:nat}

(xs:!list_vt(a,n)):intn=let

funloop

{i,j:nat|i+j==n}.<i>.

(xs:!list_vt(a,i),j:intj):int(n)=

case+xsof

|list_vt_cons(_,xs1)=>loop(xs1,j+1)|list_vt_nil()=>j

//endof[loop]

in

loop(xs,0)

end//endof[length]

Page 291: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Theinterfaceof length indicatesthat length<T> returnsanintegerequaltoIwhenappliedtoalistofthetype list_vt(T,I) ,whereTandIareatypeandaninteger,respectively.Notethatthesymbol ! infrontofthetypeofafunctionargumentindicatesthattheargumentiscall-by-valueanditispreservedafter a call to the function. The function loop inside the bodyof length is tail-recursive.Given alinearlistandaninteger, loop returnsthesumofthelengthofthelistandtheinteger.Inthebodyofloop , if xs matches thepattern list_vt_cons(_, xs1) , then thename xs1 isbound to the tailof xs .Notethat xs1 isavalue(insteadofavariable),anditisnotallowedthat xs1 bemodifiedintoanothervalue(ofadifferenttype).

Suppose thatwedowant tomodify thecontent stored in a list-node.For instance,wemaywant todouble the value of each integer stores in a linear integer list. The following code implements afunctionnamed list_vt_2x thatdoespreciselythis:

fun

list_vt_2x{n:nat}

(xs:!list_vt(int,n)>>_):void=

(

case+xsof

|@list_vt_cons

(x,xs1)=>let

val()=x:=2*x

val()=list_vt_2x(xs1)

prval()=fold@(xs)

in

//nothing

end//endof[list_vt_cons]

|list_vt_nil()=>()

)(*endof[list_vt_2x]*)

GivenatypeT,thenotation( !T>>_ )isashorthandfor( !T>>T ).Notethatthespecialsymbol @ infrontofthepattern list_vt_cons(x,xs1) meansunfolding.If xs matchesthispattern,then x and xs1areboundtothepointerspointingtosomememorylocationsL1andL2wheretheheadandtailof xsarestored,respectively,andthetypeof xs changesinto list_vt_cons_unfold(L0,L1,L2) forL0beingthe location of the list-node referred to by xs . In the body of the clause guarded by the patternlist_vt_cons(x,xs1) , x and xs1 aretreatedasvariables(whichareaformofleft-value).Thespecialprooffunction fold@ iscalledon xs tofolditplustheproofsofat-viewsattachedtoL1andL2intoalinearlist.

Letusnowseeanexamplewherelinearlist-nodesareexplicitlyfreed:

Page 292: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

fun{

a:t@ype

}list_vt_free

{n:nat}.<n>.

(xs:list_vt(a,n)):void=

(

case+xsof

|~list_vt_cons

(x,xs1)=>list_vt_free(xs1)

|~list_vt_nil((*void*))=>()

)(*endof[list_vt_free]*)

Givenalinearlist,thefunction list_vt_free freesallthenodesinthelist.Letusgooverthebodyoflist_vt_free carefully.If xs matchesthepattern list_vt_cons(x,xs1) ,thenthenames x and xs1 areboundtotheheadandtailof xs ,respectively;thespecialsymbol ~ infrontofthepatternindicatesthatthelist-nodereferredtoby xs isfreedimmediatelyafter xs matchesthepattern.If xs matchesthe pattern list_vt_nil() , no bindings are generated; the special symbol ~ in front of the patternindicatesthatthelist-nodereferredtoby xs isfreed;nothinginthiscaseisactuallyfreedatrun-timeas list_vt_nil ismappedtothenullpointer.

Itisalsopossibletousethespecialfunction free@ toexplicitlyfreeanode(alsocalledaskeleton)leftinalinearvariableafterthevariablematchesapatternformedwithaconstructorassociatedwithsomedataviewtype.Forinstance,thefollowingcodegivesanotherimplementationof list_vt_free :

fun{

a:t@ype

}list_vt_free

{n:nat}.<n>.(xs:list_vt(a,n)):void=

case+xsof

|@list_vt_cons

(x,xs1)=>let

valxs1_=xs1//[xs1_]isthevaluestoredin[xs1]

val((*void*))=free@{a}{0}(xs)inlist_vt_free(xs1_)

end//endof[list_vt_cons]

|@list_vt_nil()=>free@{a}(xs)

//endof[list_vt_free]

Asitcanbeabittrickytouse free@ inpractice,Ipresentmoredetailsasfollows.First,letusnotethatthe constructors list_vt_nil and list_vt_cons associated with list_vt are assigned the followingtypes:

list_vt_nil://onequantifier

Page 293: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

{a:t@ype}()->list_vt(a,0)

list_vt_cons://twoquantifiers

{a:t@ype}{n:nat}(a,list_vt(a,n))->list_vt(a,n+1)

If free@ isappliedtoanodeofthetype list_vt_nil() ,itneedsonestaticargument,whichisatype,toinstantiatethequantifierinthetypeoftheconstructor list_vt_nil .If free@ isappliedtoanodeofthetype list_vt_cons_unfold(L0, L1, L2) , then it needs two static arguments, which are a type and aninteger,toinstantiatethetwoquantifiersinthetypeoftheconstructor list_vt_cons .Inthecasewherethe type of xs is list_vt_cons_unfold(L0, L1, L2) , typechecking the call free@{a}{0}(xs) implicitlyconsumesaproofoftheat-view a?@L1 andanotherproofoftheat-view list_vt(a,0)?@L2 .Asthereisnodifferencebetween list_vt(T, 0)? and list_vt(T, I)? for anyT and I, the static argument 0 ischoseninthecode.Asamatteroffact,anynaturalnumbercanbeusedinplaceof0asthesecondstaticargumentof free@ .

LinearList-Reversing

Thefollowingcodeimplementsafunction reverse thatturnsagivenlinearlistintoitsreverse:

fn{

a:t@ype

}reverse{n:nat}

(

xs:list_vt(a,n)

):list_vt(a,n)=let

funrevapp

{i,j:nat|i+j==n}.<i>.

(

xs:list_vt(a,i),ys:list_vt(a,j)

):list_vt(a,n)=

case+xsof

|@list_vt_cons

(_,xs1)=>let

valxs1_=xs1

val()=xs1:=ys

prval()=fold@(xs)

in

revapp(xs1_,xs)

end//endof[list_vt_cons]

|~list_vt_nil((*void*))=>ys

//endof[revapp]

in

revapp(xs,list_vt_nil)

Page 294: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

end//endof[reverse]

Thetypeassignedto reverse indicatesthatthefunctionreturnsalinearlistofthesamelengthastheoneitconsumes.Notethattheinnerfunction revapp istail-recursive.Thisimplementationoflinearlist-reversingdirectlycorrespondstotheonepresentedpreviouslythatisbasedthedataview slseg_v(forsingly-linkedlistsegments).Comparingthetwoimplementations,wecanseethattheonebasedon dataviewtype is significantly simplified at the level of types. For instance, there is no explicitmentioningofpointersinthetypesassignedtofunctions reverse and revapp .

LinearList-Appending

Thefollowingcodeimplementsafunction append thatconcatenatestwogivenlinearlistsintoone:

fn{

a:t@ype

}append{m,n:nat}

(

xs:list_vt(a,m)

,ys:list_vt(a,n)

):list_vt(a,m+n)=let

funloop{m,n:nat}.<m>.//[loop]istail-recursive

(

xs:&list_vt(a,m)>>list_vt(a,m+n),ys:list_vt(a,n)

):void=

case+xsof

|@list_vt_cons

(_,xs1)=>let

val()=loop(xs1,ys)infold@(xs)

end//endof[list_vt_cons]

|~list_vt_nil((*void*))=>xs:=ys

//endof[loop]

varxs:List_vt(a)=xs//creatingaleft-valuefor[xs]

val()=loop(xs,ys)

in

xs

end//endof[append]

As thecall fold@(xs) in thebodyof the function loop is erased after typechecking, loop is a tail-recursive function. Therefore, append can be called on lists of any length without the concern ofpossible stackoverflow.The type for the first argumentof loop beginswith the symbol & , whichindicatesthatthisargumentiscall-by-reference.Thetypeof loop simplymeansthatitsfirstargument

Page 295: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ischangedfromalistoflength m intoalistoflength m+n whileitssecondargumentisconsumed.

This implementation of list append essentially corresponds to the one presented previously that isbasedon thedataview slseg_v .Comparing these two,wecaneasilysee that theaboveone ismuchsimplerandcleaner,demonstratingconcretelysomeadvantageofdataviewtypesoverdataviews.

This is also a good place for me to mention a closely related issue involving (functional) listconstructionandtail-recursion.Followingisatypicalimplementationoffunctioallistconcatenation:

fun{

a:t@ype

}append1{m,n:nat}

(

xs:list(a,m),ys:list(a,n)

):list(a,m+n)=

case+xsof

|list_cons(x,xs)=>list_cons(x,append1(xs,ys))

|list_nil()=>ys

//endof[append1]

Clearly, append1 isnottail-recursive,whichmeansthatitmaycausestackoverflowatrun-timeifitsfirstargumentisverylong(e.g.,containing1millionelements).Thereis,however,adirectandtype-safe way in ATS to implement functional list concatenation in a tail-recursive manner, thuseliminating the concernof potential stackoverflow.For instance, the following implementationofappend2 returnstheconcatenationoftwogivenfunctionallistswhilebeingtail-recursive:

fun{

a:t@ype

}append2{m,n:nat}

(

xs:list(a,m),ys:list(a,n)

):list(a,m+n)=let

//

funloop

{m,n:nat}.<m>.

(

xs:list(a,m),ys:list(a,n)

,res:&(Lista)?>>list(a,m+n)

):void=

(

case+xsof

|list_cons

(x,xs)=>let

Page 296: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

val()=

res:=list_cons{a}{0}(x,_)

val+list_cons(_,res1)=res

val()=loop(xs,ys,res1)

prval((*void*))=fold@(res)

in

//nothing

end//endof[list_cons]

|list_nil()=>(res:=ys)

)(*endof[loop]*)

//

varres:List(a)

val()=loop(xs,ys,res)

//

in

res

end//endof[append2]

Duringtypechecking,theexpression list_cons{a}{0}(x,_) isassignedthe(linear)type list_cons(L0,L1,L2) forsomeaddressesL0,L1andL2whileaproofoftheat-view a@L1 andanotherproofoftheat-view list(a, 0)?@L2 are put into the store for currently available proofs. Note that the specialsymbol _ simply indicates that the tail of the newly constructed list is uninitialized. A partiallyinitializedlistofthetype list_cons(L0,L1,L2) isguaranteedtomatchthepattern list_cons(_,res1) ,yieldingabindingbetween res1 andthepointerpointingtoL2wherethe(possiblyuninitialized)tailofthelistisstored.When fold@ iscalledonavariableofthetype list_cons(L0,L1,L2) ,itchangesthetypeofthevariableto list(T,N+1) byconsumingaproofoftheat-view T@L1 andanotherproofoftheat-view list(T,N)@L2 ,whereTandNareatypeandaninteger,respectively.

Summary

With dataviewtypes, we can largely retain the convenience of pattern matching associated withdatatypeswhilesupportingexplicitmemorymanagement.Comparedtodataviews,dataviewtypesareless general.However, if a dataviewtype canbe employed to solve a problem, then the solution isoftensignificantlysimplerandcleanerthananalternativedataview-basedone.

Page 297: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:Merge-SortonLinearLists

When merge-sort is employed to sort an array of elements, it requires additional memoryproportionate to thesizeof thearray inorder tomove theelementsaround,which isconsideredasignificant weakness of merge-sort. However, merge-sort does not have this requirement when itoperatesonalinearlist.Ipresentasfollowsanimplementationofmerge-sortonlinearliststhatcanreadily rival its counterpart in C in terms of both time-efficiency and memory-efficiency. Theinvariants captured in this implementation and the easiness to capture them should provide strongevidencethatatteststoATSbeingaprogramminglanguagecapableofenforcinggreatprecisioninpracticalprogramming.

Letusfirstintroduceatypedefinitionandaninterfaceforafunctiontemplatethatcompareselementsinliststobesorted:

//

typedefcmp(a:t@ype)=(&a,&a)->int

//

fun{a:t@ype}compare(x:&a,y:&a,cmp:cmp(a)):int

//

Theinterfaceformerge-sortisgivenasfollows:

fun{

a:t@ype

}mergeSort{n:nat}

(xs:list_vt(a,n),cmp:cmpa):list_vt(a,n)

//endof[mergeSort]

The first argument of mergeSort is a linear list (to be sorted) and the second one a function forcomparingtheelementsinthelinearlist.Clearly,theinterfaceof mergeSort indicates that mergeSortconsumes its first argument and then returns a linear list that is of the same length as its firstargument.Asistobecomeclear,thereturnedlinearlistisconstructedwiththenodesoftheconsumedone. Inparticular, the implementationof mergeSort givenas followsdoesnot involveanymemoryallocationordeallocation.

Thefunctiontemplateformergingtwosortedlistsintooneisgivenasfollows:

fun{

a:t@ype

}merge{m,n:nat}.<m+n>.

(

Page 298: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

xs:list_vt(a,m),ys:list_vt(a,n)

,res:&List_vt(a)?>>list_vt(a,m+n)

,cmp:cmpa

):void=

case+xsof

|@list_vt_cons(x,xs1)=>(

case+ysof

|@list_vt_cons(y,ys1)=>let

valsgn=compare<a>(x,y,cmp)

in

ifsgn<=0thenlet//stablesorting

val()=res:=xs

valxs1_=xs1

prval()=fold@(ys)

val()=merge<a>(xs1_,ys,xs1,cmp)

in

fold@(res)

endelselet

val()=res:=ys

valys1_=ys1

prval()=fold@(xs)

val()=merge<a>(xs,ys1_,ys1,cmp)

in

fold@(res)

end//endof[if]

end(*endof[list_vt_cons]*)

|~list_vt_nil()=>(fold@(xs);res:=xs)

)//endof[list_vt_cons]

|~list_vt_nil()=>(res:=ys)

//endof[merge]

Unlike theonegiven inaprevious functional implementation, this implementationof merge is tail-recursiveandthusisguaranteedtobetranslatedintoaloopinCbytheATScompiler.Thismeansthattheconcernof merge beingunabletohandleverylonglists(e.g.,containing1millionelements)duetopotentialstackoverflowiseliminated.

Thenextfunctiontemplateisforsplittingagivenlinearlistsintotwo:

fun{

a:t@ype

}split{n,k:nat|k<=n}.<n-k>.

(

xs:&list_vt(a,n)>>list_vt(a,n-k),nk:int(n-k)

):list_vt(a,k)=

ifnk>0thenlet

Page 299: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

val+@list_vt_cons(_,xs1)=xs

valres=split<a>(xs1,nk-1);prval()=fold@(xs)

in

res

endelselet

valres=xs;val()=xs:=list_vt_nil()inres

end//endof[if]

//endof[split]

Notethattheimplementationof split isalsotail-recursive.

Thefollowingfunctiontemplate msort takesalinearlist,itslengthandacomparsionfunction,anditreturnsasortedversionofthegivenlinearlist:

fun{

a:t@ype

}msort{n:nat}.<n>.

(

xs:list_vt(a,n),n:intn,cmp:cmp(a)

):list_vt(a,n)=

ifn>=2thenlet

valn2=half(n)

valn3=n-n2

varxs=xs//lvaluefor[xs]

valys=split<a>(xs(*cbr*),n3)

valxs=msort<a>(xs,n3,cmp)

valys=msort<a>(ys,n2,cmp)

varres:List_vt(a)//uninitialized

val()=merge<a>(xs,ys,res(*cbr*),cmp)

in

res

endelsexs

//endof[msort]

Thesecondargumentof msort ispassedsothatthelengthofthelistbeingsorteddoesnothavetobecomputeddirectlybytraversingthelistwheneachrecursivecallto msort ismade.

Finally, mergeSort canbeimplementedwithacallto msort :

implement{a}

mergeSort(xs,cmp)=msort<a>(xs,length(xs),cmp)

By inspecting the implementation of split and merge , we can readiy see that mergeSort performsstablesorting,thatis,itpreservestheorderofequalelementsduringsorting.

Page 300: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Pleasefindon-line the entiretyof the codepresented in this sectionplus someadditional code fortesting.

Page 301: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:InsertionSortonLinearLists

Ipresentastandardimplementationofinsertionsortonlinearlistsinthissection.Theinterfaceforinsertionsortisgivenasfollows:

fun{

a:t@ype

}insertionSort{n:nat}

(xs:list_vt(a,n),cmp:cmpa):list_vt(a,n)

//endof[insertionSort]

Like mergeSort , insertionSort isimplementedinamannerthatmakesnouseofmemoryallocationordeallocation.Given a linear list, insertionSort essentially shuffles the nodes in the list to form asortedlist.

Thefollowingcodeimplementsafunction insord thatinsertsagivenlist-nodeintoasortedlinearlisttoformanothersortedlinearlist:

fun{

a:t@ype

}insord

{l0,l1,l2:addr}{n:nat}

(

pf1:a@l1

,pf2:list_vt(a,0)?@l2

|xs0:&list_vt(a,n)>>list_vt(a,n+1)

,nx0:list_vt_cons_unfold(l0,l1,l2),p1:ptr(l1),p2:ptr(l2)

,cmp:cmp(a)

):void=

(

case+xs0of

|@list_vt_cons

(x0,xs1)=>let

valsgn=compare<a>(x0,!p1,cmp)

in

ifsgn<=0//HX:forstableness:[<=]insteadof[<]

thenlet

val()=insord<a>(pf1,pf2|xs1,nx0,p1,p2,cmp)

prval()=fold@(xs0)

in

//nothing

end//endof[then]

elselet

prval()=fold@(xs0)

Page 302: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

val()=(!p2:=xs0;xs0:=nx0)

prval()=fold@(xs0)

in

//nothing

end//endof[else]

//endof[if]

end//endof[list_vt_cons]

|~list_vt_nil()=>

{

val()=xs0:=nx0

val()=!p2:=list_vt_nil()

prval()=fold@(xs0)

}

)(*endof[insord]*)

The implementation of insord is tail-recursive. The type assigned to insord indicates that theargumentxs0of insord iscall-by-reference.Ifxs0storesalistoflengthnwhen insord iscalled,thenitstoresalistoflengthn+1when insord returns.Theargumentsnx0,p1andp2arecall-by-value,andtheyshouldbeboundtoalist-nodeandthefirstandsecondfieldsinthelist-node,respectively,whenacallto insord initiates.Theproofargumentspf1andpf2areneededsothatthepointersboundtop1andp2canbeaccessedandupdated.

Thefunctiontemplate insertionSort cannowbereadilyimplementedbased insord :

implement{a}

insertionSort

(xs,cmp)=let

//

funloop{m,n:nat}

(

xs:list_vt(a,m)

,ys:&list_vt(a,n)>>list_vt(a,m+n)

,cmp:cmp(a)

):void=

case+xsof

|@list_vt_cons

(x,xs1)=>let

valxs1_=xs1

val((*void*))=

insord<a>(view@x,view@xs1|ys,xs,addr@x,addr@xs1,cmp)

//endof[va]

in

loop(xs1_,ys,cmp)

end//endof[list_vt_cons]

Page 303: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

|~list_vt_nil((*void*))=>()

//

varys=list_vt_nil{a}()

val()=loop(xs,ys,cmp)

//

in

ys

end//endof[insertionSort]

Clearly,thisimplementationof insertionSort istail-recursive.WhileinsertionsortisofO(n^2)-timecomplexity,itisoftenmoreefficientthanmerge-sortorquick-sortwhensortingveryshortlists.Forinstance,wemayimplement msort (whichiscalledby mergeSort )asfollowsbytakingadvantageoftheefficiencyof insertionSort onshortlists:

fun{

a:t@ype

}msort{n:nat}.<n>.

(

xs:list_vt(a,n)

,n:intn,cmp:cmp(a)

):list_vt(a,n)=let

//

//cutoffisselectedtobe10

//

in

ifn>10thenlet

valn2=half(n)

valn3=n-n2

varxs=xs//lvaluefor[xs]

valys=split<a>(xs,n3)

valxs=msort<a>(xs,n3,cmp)

valys=msort<a>(ys,n2,cmp)

varres:List_vt(a)//uninitialized

val()=merge<a>(xs,ys,res(*cbr*),cmp)

in

res

endelseinsertionSort<a>(xs,cmp)

end//endof[msort]

Notethatthestablenessof mergeSort ismaintainedas insertionSort alsoperformsstablesorting.

Pleasefindtheentirecodeinthissectionplussomeadditionalcodefortestingon-line.

Page 304: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:Quick-SortonLinearLists

Inthissection,Igiveanimplementationofquick-sortonlinearlists.Whilelist-basedquick-sortmaynot be a preferred sorting method in practice, its implementation is nonetheless interesting. Theinterfaceforquick-sortisgivenasfollows:

fun{a:t@ype}

quickSort{n:nat}(xs:list_vt(a,n),cmp:cmpa):list_vt(a,n)

Like the implementationof mergeSort and insertionSort , the implementationof quickSort given asfollowsmakesnouseofmemoryallocationanddeallocation.

Thefollowingcodeimplementsafunction takeout_node_at thattakesoutanodefromalinearlistatagivenposition:

fun{a:t@ype}

takeout_node_at

{n:int}{k:nat|k<n}

(

xs:&list_vt(a,n)>>list_vt(a,n-1),k:int(k)

):list_vt_cons_pstruct(a,ptr?)=

(

//

ifk>0thenlet

val+@list_vt_cons(x,xs1)=xs

valres=takeout_node_at<a>(xs1,k-1)

prval()=fold@(xs)

in

res

endelselet

val+@list_vt_cons(x,xs1)=xs

valnx=xs

val()=xs:=xs1

in

$UNSAFE.castvwtp0((view@x,view@xs1|nx))//HX:thisisasafecast

end//endof[if]

//

)(*endof[takeout_node_at]*)

Assume that a data constructor named foo is associated with a dataviewtype. Then there is acorresponding viewtype construtor of the name foo_pstruct that takes n types to form a viewtype,wherenisthearityoffoo.Forinstance,thereisaviewtypeconstructor list_vt_cons_pstruct thattakes2typesT1andT2toformaviewtype list_vt_cons_pstruct(T1,T2) .Thisviewtypeisfora list-node

Page 305: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

createdbyacallto list_vt_cons suchthatthetwoargumentsof list_vt_cons areoftypesT1andT2.Essentially, list_vt_cons_pstruct(T1, T2) stands for list_vt_cons_unfold(L0, L1, L2) for someaddressesL0,L1andL2plustwoviews T1@L1 and T2@L2 .

Akeystepinquick-sortliesinpartitioningalinearlistbasedonagivenpivot.Thisstepisfulfilledbythefollowingcodethatimplementsafunctiontemplatenamed partition :

fun{

a:t@ype

}partition{n,r1,r2:nat}

(

xs:list_vt(a,n),pvt:&a

,r1:int(r1),res1:list_vt(a,r1),res2:list_vt(a,r2)

,cmp:cmp(a)

):[n1,n2:nat|n1+n2==n+r1+r2]

(int(n1),list_vt(a,n1),list_vt(a,n2))=

(

case+xsof

|@list_vt_cons

(x,xs_tail)=>let

valxs_tail_=xs_tail

valsgn=compare<a>(x,pvt,cmp)

in

ifsgn<=0thenlet

valr1=r1+1

val()=xs_tail:=res1

prval()=fold@(xs)

in

partition<a>(xs_tail_,pvt,r1,xs,res2,cmp)

endelselet

val()=xs_tail:=res2

prval()=fold@(xs)

in

partition<a>(xs_tail_,pvt,r1,res1,xs,cmp)

end//endof[if]

end(*endof[list_vt_cons]*)

|~list_vt_nil((*void*))=>(r1,res1,res2)

)(*endof[partition]*)

Theimplementationof partition istail-recursive.Givenalinearlistandapivot, partition returnsatuple(r1,res1,res2)suchthatres1containseveryelementinthelistthatislessthanorequaltothepivot, res2contains the rest, and r1 is the lengthof res1.Theway inwhich thenodesof thegivenlinearlistaremovedintores1andres2isquiteaninterestingaspectofthisimplementation.

Page 306: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Bymakinguseof takeout_node_at and partition ,wecanreadilyimplement quickSort asfollows:

implement

{a}(*tmp*)

quickSort

(xs,cmp)=let

//

funsort{n:nat}

(

xs:list_vt(a,n),n:intn

):list_vt(a,n)=

(

ifn>10thenlet

valn2=half(n)

varxs=xs

valnx=takeout_node_at<a>(xs,n2)

val+list_vt_cons(pvt,nx_next)=nx

val(n1,xs1,xs2)=

partition<a>(xs,pvt,0,list_vt_nil,list_vt_nil,cmp)

valxs1=sort(xs1,n1)

valxs2=sort(xs2,n-1-n1)

val()=nx_next:=xs2

prval()=fold@(nx)

in

list_vt_append(xs1,nx)

endelseinsertionSort<a>(xs,cmp)

)(*endof[sort]*)

//

in

sort(xs,list_vt_length(xs))

end//endof[quickSort]

Notethatthepivotforeachroundistakenfromthemiddleofthelistbeingsorted,whichcanbetime-consumingastakingoutanodefromthemiddleofalistisO(n)-time.Thisissuecanbeaddressedbyalwayschoosing thefirstelement tobe thepivot.However,doingsocanoften lead todegeneratedO(n^2)-timeperformanceofquick-sortinpractice.

Pleasefindtheentirecodeinthissectionplussomeadditionalcodefortestingon-line.

Page 307: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

LinearBinarySearchTrees

Abinarysearchtreewithrespecttoagivenorderingisabinarytreesuchthatthevaluestoredineachnodeinsidethetreeisgreaterthanorequaltothosestoredintheleftchildofthenodeandlessthanorequaltothosestoredintherightchildofthenode.Binarysearchtreesareacommondatastructureforimplementingfinitemaps.

AfamilyofbinarytreesaresaidtobebalancedifthereisafixedconstantC(fortheentirefamily)suchthattheratiobetweenthelengthofalongestpathandthelengthofashortestpathisboundedbyCforeverytreeinthefamily.Forinstance,commonexamplesofbalancedbinarytreesincludeAVLtreesandred-blacktrees.Finitemapsbasedonbalancedbinarysearchtreessupportguaranteedlog-timeinsertionanddeletionoperations,thatis,thetimetocompletesuchanoperationisO(log(n))intheworstcase,wherenisthesizeofthemap.

In this section, I am to implement several basic operations on linear binary search trees, furtherillustratingsomeuseofdataviewtypes.Letus firstdeclareas followsadataviewtype bstree_vt forlinearbinary(search)trees:

datavtype

bstree_vt(a:t@ype+,int)=

|bstree_vt_nil(a,0)of()

|{n1,n2:nat}

bstree_vt_cons(a,n1+n2+1)of(bstree_vt(a,n1),a,bstree_vt(a,n2))

//endof[bstree_vt]

Notethattheintegerindexof bstree_vt capturesthesizeinformationofabinary(search)tree.Therearetwoconstructors bstree_vt_cons and bstree_vt_nil associatedwith bstree_vt .Itshouldbepointedout that the treecreatedby bstree_vt_nil isemptyand thusnota leaf,whichon theotherhand isanode whose left and right children are both empty. As a simple example, the following functiontemplate size computesthesizeofagiventree:

fun{

a:t@ype

}size{n:nat}.<n>.

(

t:!bstree_vt(a,n)

):int(n)=

case+tof

|bstree_vt_nil()=>0

|bstree_vt_cons

(tl,_,tr)=>1+size(tl)+size(tr)

Page 308: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

//endof[size]

Assume that we have a binary search tree with repect to some ordering. If a predicate P on theelementsstoredinthetreepossessesthepropertythatP(x1)impliesP(x2)wheneverx1islessthanx2(accordingtotheordering),thenwecanlocatetheleastelementinthetreethatsatisfiesthepredicateP by employing so-called binary search as is demonstrated in the following implementation ofsearch :

fun{

a:t@ype

}search

{n:nat}.<n>.

(

t:!bstree_vt(a,n),P:(&a)-<cloref>bool

):Option_vt(a)=

case+tof

|@bstree_vt_cons

(tl,x,tr)=>

ifP(x)thenlet

valres=search(tl,P)

valres=(

case+resof

|~None_vt()=>Some_vt(x)|_=>res

):Option_vt(a)

in

fold@(t);res

endelselet

valres=search(tr,P)infold@(t);res

end//endof[if]

|@bstree_vt_nil()=>(fold@(t);None_vt())

//endof[search]

Clearly,iftheargument t of search rangesoverafamilyofbalancedtrees,thenthetime-complexityof search isO(log(n))(assumingthat P isO(1)).

Letusnextseesomecodeimplementinganoperationthatinsertsagivenelementintoabinarysearchtree:

fun{

a:t@ype

}insert{n:nat}.<n>.

(

t:bstree_vt(a,n),x0:&a,cmp:cmp(a)

):bstree_vt(a,n+1)=

Page 309: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

case+tof

|@bstree_vt_cons

(tl,x,tr)=>let

valsgn=compare<a>(x0,x,cmp)

in

ifsgn<=0thenlet

val()=tl:=insert(tl,x0,cmp)

in

fold@(t);t

endelselet

val()=tr:=insert(tr,x0,cmp)

in

fold@(t);t

end(*endof[if]*)

end//endof[bstree_vt_cons]

|~bstree_vt_nil()=>

bstree_vt_cons(bstree_vt_nil,x0,bstree_vt_nil)

//endof[bstree_vt_nil]

//endof[insert]

Wheninsertinganelement,thefunctiontemplate insert extendsthegiventreewithanewleafnodecontaining the element, and this form of insertion is often referred to as leaf-insertion. There isanotherformofinsertionoftenreferredtoasroot-insertion,whichalwaysputsattherootpositionthe new node containing the inserted element. The following function template insertRT isimplementedtoperformastandardroot-insertionoperation:

fun{

a:t@ype

}insertRT{n:nat}.<n>.

(

t:bstree_vt(a,n),x0:&a,cmp:cmp(a)

):bstree_vt(a,n+1)=

case+tof

|@bstree_vt_cons

(tl,x,tr)=>let

valsgn=compare<a>(x0,x,cmp)

in

ifsgn<=0thenlet

valtl_=insertRT(tl,x0,cmp)

val+@bstree_vt_cons(_,tll,tlr)=tl_

val()=tl:=tlr

prval()=fold@(t)

val()=tlr:=t

in

fold@(tl_);tl_

Page 310: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

endelselet

valtr_=insertRT(tr,x0,cmp)

val+@bstree_vt_cons(trl,_,trr)=tr_

val()=tr:=trl

prval()=fold@(t)

val()=trl:=t

in

fold@(tr_);tr_

end

end//endof[bstree_vt_cons]

|~bstree_vt_nil()=>

bstree_vt_cons(bstree_vt_nil,x0,bstree_vt_nil)

//endof[bstree_vt_nil]

//endof[insertRT]

Thecodeimmediatelyfollowingthefirstrecursivecallto insertRT performsarighttreerotation.LetususeT(tl,x,tr)foratreesuchthatitsrootnodecontainstheelementxanditsleftandrightchildrenaretlandtr,respectively.ThenarightrotationturnsT(T(tll,xl,tlr),x,tr)intoT(tll,xl,T(tlr,x,tr)).Thecodeimmediatelyfollowingthesecondrecursivecallto insertRT performsalefttreerotation,whichturnsT(tl,x,T(trl,xr,trr))intoT(T(tl,x,tlr),xr,trr).

Tofurtherillustratetreerotations,Ipresentasfollowstwofunctiontemplates lrotate and rrotate ,whichimplementtheleftandrighttreerotations,respectively:

fn{

a:t@ype

}lrotate

{l,l_tl,l_x,l_tr:addr}

{nl,nr:int|nl>=0;nr>0}

(

pf_tl:bstree_vt(a,nl)@l_tl

,pf_x:a@l_x

,pf_tr:bstree_vt(a,nr)@l_tr

|t:bstree_vt_cons_unfold(l,l_tl,l_x,l_tr)

,p_tl:ptrl_tl

,p_tr:ptrl_tr

):bstree_vt(a,1+nl+nr)=let

valtr=!p_tr

val+@bstree_vt_cons(trl,_,trr)=tr

val()=!p_tr:=trl

prval()=fold@(t);val()=trl:=t

in

fold@(tr);tr

end//endof[lrotate]

Page 311: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

fn{

a:t@ype

}rrotate

{l,l_tl,l_x,l_tr:addr}

{nl,nr:int|nl>0;nr>=0}

(

pf_tl:bstree_vt(a,nl)@l_tl

,pf_x:a@l_x

,pf_tr:bstree_vt(a,nr)@l_tr

|t:bstree_vt_cons_unfold(l,l_tl,l_x,l_tr)

,p_tl:ptrl_tl

,p_tr:ptrl_tr

):bstree_vt(a,1+nl+nr)=let

valtl=!p_tl

val+@bstree_vt_cons(tll,x,tlr)=tl

val()=!p_tl:=tlr

prval()=fold@(t);val()=tlr:=t

in

fold@(tl);tl

end//endof[rrotate]

Given4addressesL0,L1,L2andL3,thetype bstree_vt_cons_unfold(L0,L1,L2,l3) isforatreenodecreated by a call to bstree_vt_cons such that the node is located at L0 and the three arguments ofbstree_vt_cons are locatedatL1,L2andL3,and theproofsfor theat-viewsassociatedwithL1,L2andL3areputinthestoreforcurrentlyavailableproofs.

The function template insertRT for root-insertion can now be implemented as follows bymakingdirectuseof lrotate and rrotate :

fun{

a:t@ype

}insertRT{n:nat}.<n>.

(

t:bstree_vt(a,n),x0:&a,cmp:cmp(a)

):bstree_vt(a,n+1)=

case+tof

|@bstree_vt_cons

(tl,x,tr)=>let

prvalpf_x=view@x

prvalpf_tl=view@tl

prvalpf_tr=view@tr

valsgn=compare<a>(x0,x,cmp)

in

ifsgn<=0thenlet

Page 312: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

val()=tl:=insertRT<a>(tl,x0,cmp)

in

rrotate<a>(pf_tl,pf_x,pf_tr|t,addr@tl,addr@tr)

endelselet

val()=tr:=insertRT<a>(tr,x0,cmp)

in

lrotate<a>(pf_tl,pf_x,pf_tr|t,addr@tl,addr@tr)

end(*endof[if]*)

end//endof[bstree_vt_cons]

|~bstree_vt_nil()=>

bstree_vt_cons(bstree_vt_nil,x0,bstree_vt_nil)

//endof[bstree_vt_nil]

//endof[insertRT]

Iwouldliketopointoutthatneither insert nor insertRT istail-recursive.Whileitisstraightforwardtogivetheformeratail-recursiveimplementation,thereisnodirectwaytodothesametothelatter.Inordertoimplementroot-insertioninatail-recursivemanner,weareinneedofbinarysearchtreeswithparentalpointers(soastoalloweachnodetogaindirectaccesstoitsparent),whichcanbedonewithdataviewsbutnotwithdataviewtypes.

Pleasefindtheentirecodeinthissectionplussomeadditionalcodefortestingon-line.

Page 313: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

TransitionfromDatatypestoDataviewtypes

Manyprogrammersarelikelytofinditaratherinvolvedtasktowritecodemanipulatingvaluesofdataviewtypes.Whenhandlingacomplexdatastructure, Imyselfoften try to firstuseadatatype tomodelthedatastructureandimplementsomefunctionalitiesofthedatastructurebasedthedatatype.Ithen change the datatype into a corresponding dataviewtype and modify the implementationaccordingly tomake itworkwith thedataviewtype. Inowpresent as followsan implementationoflinear red-black trees that is directly based on a previous implementation of functional red-blacktrees, illustrating concretely a kind of gradual transition from datatypes to dataviewtypes that cangreatly reduce the level of difficulty onemay otherwise encounter in an attempt to programwithdataviewtypesdirectly.

Thefollowingdeclarationofdataviewtype rbtree isidenticaltothepreviousdeclarationofdatatyperbtree exceptthekeyword datavtype beingnowusedinsteadofthekeyword datatype :

#defineBLK0;#defineRED1

sortdefclr={c:int|0<=c;c<=1}

datavtyperbtree

(

a:t@ype+,int(*c*),int(*bh*),int(*v*)

)=//elementtype,color,blackheight,violations

|rbtree_nil(a,BLK,0,0)of((*void*))

|{c,cl,cr:clr}{bh:nat}{v:int}

{c==BLK&&v==0||c==RED&&v==cl+cr}

rbtree_cons(a,c,bh+1-c,v)of(intc,rbtree0(a,cl,bh),a,rbtree0(a,cr,bh))

//endof[rbtree]

whererbtree0(a:t@ype,c:int,bh:int)=rbtree(a,c,bh,0)

Atthefirstsight,thefollowingfunctiontemplate insfix_l isgreatlymore involvedthatapreviousversionofthesamename(formanipulatingfunctionalred-blacktrees):

fn{

a:t@ype

}insfix_l//rightrotation

{cl,cr:clr}

{bh:nat}{v:nat}

{l,l_c,l_tl,l_x,l_tr:addr}

(

pf_c:int(BLK)@l_c

,pf_tl:rbtree(a,cl,bh,v)@l_tl

Page 314: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

,pf_x:a@l_x

,pf_tr:rbtree(a,cr,bh,0)@l_tr

|t:rbtree_cons_unfold(l,l_c,l_tl,l_x,l_tr)

,p_tl:ptr(l_tl)

):[c:clr]rbtree0(a,c,bh+1)=let

#defineBBLK

#defineRRED

#definenilrbtree_nil

#defineconsrbtree_cons

in

case+!p_tlof

|@cons(clasR,tllas@cons(cllasR,_,_,_),_,tlr)=>let

//

val()=cll:=B

prval()=fold@(tll)

//

valtl=!p_tl

val()=!p_tl:=tlr

prval()=fold@(t)

val()=tlr:=t

//

in

fold@(tl);tl

end//endof[cons(R,cons(R,...),...)]

|@cons(clasR,tll,_,tlras@cons(clrasR,tlrl,_,tlrr))=>let

//

valtl=!p_tl

val()=!p_tl:=tlrr

prval()=fold@(t)

val()=tlrr:=t

//

valtlr_=tlr

val()=tlr:=tlrl

val()=cl:=B

prval()=fold@(tl)

val()=tlrl:=tl

//

in

fold@(tlr_);tlr_

end//endof[cons(R,...,cons(R,...))]

|_(*rest-of-cases*)=>>(fold@(t);t)

end//endof[insfix_l]

However,Iwouldliketopointoutthattheinterfacefortheabove insfix_l isadirecttranslationoftheinterfacefortheprevious insfix_l .Inotherwords,thepreviouslycapturedrelationbetweenatreebeingrotatedandtheoneobtainedfromapplying insfix_l toitalsoholdsinthesettingoflinearred-

Page 315: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

black trees.Thevery same statement canbemade about the following function template insfix_r ,whichispreciselyamirrorimageof insfix_l :

fn{

a:t@ype

}insfix_r//leftrotation

{cl,cr:clr}

{bh:nat}{v:nat}

{l,l_c,l_tl,l_x,l_tr:addr}(

pf_c:int(BLK)@l_c

,pf_tl:rbtree(a,cl,bh,0)@l_tl

,pf_x:a@l_x

,pf_tr:rbtree(a,cr,bh,v)@l_tr

|t:rbtree_cons_unfold(l,l_c,l_tl,l_x,l_tr)

,p_tr:ptr(l_tr)

):[c:clr]rbtree0(a,c,bh+1)=let

#defineBBLK

#defineRRED

#definenilrbtree_nil

#defineconsrbtree_cons

in

case+!p_trof

|@cons(crasR,trl,_,trras@cons(crrasR,_,_,_))=>let

//

val()=crr:=B

prval()=fold@(trr)

//

valtr=!p_tr

val()=!p_tr:=trl

prval()=fold@(t)

val()=trl:=t

//

in

fold@(tr);tr

end//endof[cons(R,...,cons(R,...))]

|@cons(crasR,trlas@cons(crrasR,trll,_,trlr),_,trr)=>let

//

valtr=!p_tr

val()=!p_tr:=trll

prval()=fold@(t)

val()=trll:=t

//

valtrl_=trl

val()=trl:=trlr

val()=cr:=B

prval()=fold@(tr)

Page 316: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

val()=trlr:=tr

//

in

fold@(trl_);trl_

end//endof[cons(R,cons(R,...),...)]

|_(*rest-of-cases*)=>>(fold@(t);t)

end//endof[insfix_r]

Ascanbeexpected,thefollowingfunctiontemplate rbtree_insert isessentiallyadirecttranslationoftheoneofthesamenameforinsertinganelementintoafunctionalred-blacktree:

extern

fun{a:t@ype}

rbtree_insert

{c:clr}{bh:nat}

(

t:rbtree0(a,c,bh),x0:&a,cmp:cmpa

):[bh1:nat]rbtree0(a,BLK,bh1)

implement{a}

rbtree_insert

(t,x0,cmp)=let

//

#defineBBLK

#defineRRED

#definenilrbtree_nil

#defineconsrbtree_cons

//

funins

{c:clr}{bh:nat}.<bh,c>.

(

t:rbtree0(a,c,bh),x0:&a

):[cl:clr;v:nat|v<=c]rbtree(a,cl,bh,v)=

(

case+tof

|@cons(

c,tl,x,tr

)=>let

prvalpf_c=view@c

prvalpf_tl=view@tl

prvalpf_x=view@x

prvalpf_tr=view@tr

valsgn=compare<a>(x0,x,cmp)

in

ifsgn<0thenlet

val[cl:int,v:int]tl_=ins(tl,x0)

Page 317: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

val()=tl:=tl_

in

if(c=B)

then(

insfix_l<a>

(pf_c,pf_tl,pf_x,pf_tr|t,addr@tl)

//endof[insfix_l]

)elselet

val()=c:=Rinfold@{a}{..}{..}{cl}(t);t

end//endof[if]

endelseifsgn>0thenlet

val[cr:int,v:int]tr_=ins(tr,x0)

val()=tr:=tr_

in

if(c=B)

then(

insfix_r<a>

(pf_c,pf_tl,pf_x,pf_tr|t,addr@tr)

//endof[insfix_r]

)elselet

val()=c:=Rinfold@{a}{..}{..}{cr}(t);t

end//endof[if]

endelse(fold@{a}{..}{..}{0}(t);t)

end//endof[cons]

|~nil()=>cons{a}{..}{..}{0}(R,nil,x0,nil)

)(*endof[ins]*)

//

valt=ins(t,x0)

//

in

//

case+tof@cons(casR,_,_,_)=>(c:=B;fold@(t);t)|_=>>t

//

end//endof[rbtree_insert]

Iliterallyimplementedtheabove rbtree_insert bymakingacopyofthepreviousimplementationofrbtree_insert for functional red-black trees and then properly modifying it to make it passtypechecking.Althoughthisprocessofcopying-and-modifyingisdifficulttobedescribedformally,itisfairlystraightforwardtofollowinpracticeasitisalmostentirelyguidedbytheerrormessagesreceivedduringtypechecking.

Pleasefindtheentirecodeinthissectionplussomeadditionalcodefortestingon-line.Achallengingaswellasrewardingexerciseisforthereadertoimplementanoperationthatdeletesanelementfromagivenlinearred-blacktree.

Page 318: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 319: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 320: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter16.AbstractViewsandViewtypesIhavesofargivenapresentationofviewsthatsolelyfocusesonat-viewsandtheviewsbuiltontopofat-views.Thisislargelyduetoat-viewsbeingtheformofmostwidelyusedviewsinpracticeandalsobeingthefirstformofviewssupportedinATS.However,otherformsofviewscanbereadilyintroduced intoATS abstractly.Even in a casewhere a view can be defined based on at-views (orother forms of views), one may still want to introduce it as an abstract view (accompanied withcertainprooffunctionsforperformingview-changes).Oftenwhattheprogrammerreallyneedsistofigureoutconceptuallywhetherabstractlydefinedviewsandprooffunctionsformanipulatingthemactuallymake sense.This is abit like arguingwhether a function is computable:There is rarely aneed, if at all, to actually encode the function as aTuring-machine to prove its being computable.IMHO,learningproperuseofabstractviewsandabstractviewtypesisanecessarystepforonetotakein order to employ linear types effectively in practice to dealwith resource-related programmingissues.

Page 321: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

SimpleLinearObjects

Objects in the physical world are conspicuously linear: They cannot be created from nothing orsimplygovanishedbyturningintonothing.Thus, it isonlynatural toassignlinear typestovaluesthatrepresentphysicalobjects.Ichoosethenamesimplelinearobjectheretorefertoalinearvaluerepresenting an object of some sort that does not contain built-in mechanism for supportinginheritance.

Letusnowtakealookataconcreteexampleofsimplelinearobject.Thefollowingcodepresentsaninterfaceforatimer(thatis,stopwatch):

//

absvtypetimer_vtype

vtypedeftimer=timer_vtype

//

funtimer_new():timer

funtimer_free(x:timer):void

funtimer_start(x:!timer):void

funtimer_finish(x:!timer):void

funtimer_pause(x:!timer):void

funtimer_resume(x:!timer):void

funtimer_get_ntick(x:!timer):uint

funtimer_reset(x:!timer):void

//

Thestateofatimerisgiventherecordtype timer_struct definedasfollows:

//

typedef

timer_struct=@{

started=bool//thetimerhasstarted

,running=bool//thetimerisrunning

//theticknumberrecordedwhenthetimer

,ntick_beg=uint//wasturnedonlasttime

,ntick_acc=uint//thenumberofaccumulatedticks

}(*endof[timer_struct]*)

//

The following linear datatype timer is declared for timers, and the abstract type timer_vtype isassumedtoequal timer :

//

datavtypetimer=

Page 322: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

TIMERof(timer_struct)

//

assumetimer_vtype=timer

//

Various functionson timerscannowbe readily implemented.Letus first see thecode forcreatingandfreeingtimers:

implement

timer_new()=let

//

valtimer=TIMER(_)

valTIMER(x)=timer

//

val()=x.started:=false

val()=x.running:=false

val()=x.ntick_beg:=0u

val()=x.ntick_acc:=0u

//

prval()=fold@(timer)

//

in

timer

end//endof[timer_new]

implement

timer_free(timer)=

letval~TIMER_=timerin(*nothing*)end

//endof[timer_free]

Thefunctionforstartingatimercanbeimplementedasfollows:

implement

timer_start

(timer)=let

val+@TIMER(x)=timer

val()=x.started:=true

val()=x.running:=true

val()=x.ntick_beg:=the_current_tick_get()

val()=x.ntick_acc:=0u

prval()=fold@(timer)

in

//nothing

end//endof[timer_start]

Page 323: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

where the_current_tick_get is a function for reading the current time (represented as a number ofticks):

externfunthe_current_tick_get():uint

Atimercanbestoppedorpaused.Thefunctionforstoppingatimercanbeimplementedasfollows:

implement

timer_finish

(timer)=let

val+@TIMER(x)=timer

val()=x.started:=false

val()=

ifx.runningthen

{

val()=x.running:=false

val()=x.ntick_acc:=

x.ntick_acc+the_current_tick_get()-x.ntick_beg

}(*endof[val]*)

prval()=fold@(timer)

in

//nothing

end//endof[timer_finish]

Atimercanbepausedandthenresumed.Thefollowingcodeimplementsthefunctionsforpausingandresumingatimer:

implement

timer_pause

(timer)=let

val+@TIMER(x)=timer

val()=

ifx.runningthen

{

val()=x.running:=false

val()=x.ntick_acc:=

x.ntick_acc+the_current_tick_get()-x.ntick_beg

}(*endof[val]*)

prval()=fold@(timer)

in

//nothing

end//endof[timer_pause]

implement

timer_resume

Page 324: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

(timer)=let

val+@TIMER(x)=timer

val()=

ifx.started&&~(x.running)then

{

val()=x.running:=true

val()=x.ntick_beg:=the_current_tick_get()

}(*endof[if]*)//endof[val]

prval()=fold@(timer)

in

//nothing

end//endof[timer_resume]

Ascanbeexpected,theamountoftimebetweenthepointwhereatimerispausedandthepointwherethetimerisresumedisnotcounted.

Itisalsopossibletoresetatimerbycallingthefunction timer_reset :

implement

timer_reset

(timer)=let

val+@TIMER(x)=timer

val()=x.started:=false

val()=x.running:=false

val()=x.ntick_beg:=0u

val()=x.ntick_acc:=0u

prval()=fold@(timer)

in

//nothing

end//endof[timer_reset]

Inordertoreadthetimeaccumulatedbyatimer,thefunction timer_get_ntick canbecalled:

implement

timer_get_ntick

(timer)=let

val+@TIMER(x)=timer

varntick:uint=x.ntick_acc

val()=

ifx.runningthen(

ntick:=ntick+the_current_tick_get()-x.ntick_beg

)(*endof[if]*)//endof[val]

prval()=fold@(timer)

in

ntick

Page 325: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

end//endof[timer_get_ntick]

A straightforward approach to implementing the_current_tick_get can be based directly on thefunction clock_gettime :

local

staload"libc/SATS/time.sats"

in(*in-of-local*)

implement

the_current_tick_get()=let

vartv:timespec//uninitialized

valerr=clock_gettime(CLOCK_REALTIME,tv)

val((*void*))=assertloc(err>=0)

prval((*void*))=opt_unsome{timespec}(tv)

in

$UNSAFE.cast2uint(tv.tv_sec)

end//endof[the_current_tick_get]

end//endof[local]

Notethatthelibraryflag -lrt maybeneededinordertohavelink-timeaccessto clock_gettime asthefunctionisin librt .

Pleasefindon-linetheentiretyofthecodepresentedinthissectionplussometestingcode.

Page 326: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

MemoryAllocationandDeallocation

The issue of memory allocation and deallocation is of paramount importance in systemsprogramming, where garabage collection (GC) at run-time may not even be allowed. Handlingmemory management safely and efficiently is a long standing problem of great challenge inprogramming,anditsnovelsolutioninATSisfirmlyrootedintheparadigmofprogrammingwiththeorem-proving(PwTP).

Thefollowingfunction malloc_gc isavailableinATSformemoryallocation:

funmalloc_gc

{n:nat}(n:size_tn)

:[l:agz](b0ytesn@l,mfree_gc_v(l)|ptrl)

//endof[malloc_gc]

Thesort agz isasubsetsortdefinedforaddressesthatarenotnull:

sortdefagz={a:addr|a>null}//[gz]forgreat-than-zero

Given an integerN, the type b0ytes(N) is a shorthand for @[byte?][N] ,which is for an array ofNuninitializedbytes.Therefore,theat-view b0ytes(N)@L isthesameasthearray-view array_v(byte?,L,N) ,whereLisamemorylocation.Theviewconstructor mfree_gc_v isabstract.ForagivenlocationL,theview mfree_gc_v(L) standsforaformofcapabilitythatallowsallocatedmemoryatlocationLtobefreed(orreclaimed)bythefollowingfunction mfree_gc :

funmfree_gc

{l:addr}{n:nat}

(pfat:b0ytes(n)@l,pfgc:mfree_gc_v(l)|p:ptrl):void

//endof[free_gc]

Notethat mfree_gc_v(L) issofarthefirstformofviewwehaveencounteredthatisnotbuiltontopofanyat-views.

Inpractice,itisrathercumbersometodealwithbytesdirectly.Thefunction ptr_alloc isavailableforallocatingmemorytostoreasinglevalue(ofcertaintype)andthefunction ptr_free fordeallocatingsuchmemory:

fun{a:vt0p}

ptr_alloc()

:<>[l:agz](a?@l,mfree_gc_v(l)|ptrl)

Page 327: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

//endof[ptr_alloc]

funptr_free

{a:t@ype}{l:addr}

(pfgc:mfree_gc_v(l),pfat:a@l|p:ptrl):<>void="mac#%"

//endof[ptr_free]

In addition, the function array_ptr_alloc is for allocatingmemory to store an array of values (ofcertaintype),andthefunction array_ptr_free isfordeallocatingsuchmemory:

fun{a:vt0p}

array_ptr_alloc

{n:int}

(

asz:size_tn

):[l:agz]

(

array_v(a?,l,n),mfree_gc_v(l)|ptrl

)//endof[array_ptr_alloc]

fun{}

array_ptr_free

{a:vt0p}{l:addr}{n:int}

(

array_v(a?,l,n),mfree_gc_v(l)|ptrl

):void//endof[array_ptr_free]

Inowgivearealisticandinterestingexampleinvolvingbotharrayallocationanddeallocation.Thefollowingtwofunctionstemplates msort1 and msort2 performmerge-sortonagivenarray:

typedefcmp(a:t@ype)=(&a,&a)->int

extern

fun{

a:t@ype

}msort1{n:nat}

(A:&(@[a][n]),n:size_tn,B:&(@[a?][n]),cmp:cmp(a)):void

//endof[msort1]

extern

fun{

a:t@ype

}msort2{n:nat}

(A:&(@[a][n]),n:size_tn,B:&(@[a?][n])>>@[a][n],cmp:cmp(a)):void

//endof[msort2]

Page 328: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Itiswell-knownthatmergingtwosortedsegmentsofagivenarrayrequiresadditionalspace.Whenmsort1 iscalledonarraysAandB,thearrayAistheonetobesortedandthearrayBissomekindofscratchareaneededtoperformmerging(ofsortedarraysegments).Whenacall to msort1 returns,thesortedversionofAisstillsotredinA.What msort2 doesissimilarbutthesortedversionofAisstoredinBwhenacallto msort2 returns.Asagoodexercise,Isuggestthattheinterestedreadertaketheefforttogiveamutuallyrecursiveimplementationof msort1 and msort2 .An implementationofmerge-sortbasedon msort1 canbereadilygivenasfollows:

extern

fun{

a:t@ype

}mergeSort{n:nat}

(A:&(@[a][n]),n:size_tn,cmp:cmp(a)):void

//endof[mergeSort]

implement

{a}(*tmp*)

mergeSort

(A,n,cmp)=let

val(pfat,pfgc|p)=array_ptr_alloc<a>(n)

val((*void*))=msort1(A,n,!p,cmp)

val((*void*))=array_ptr_free(pfat,pfgc|p)

in

//nothing

end//endof[mergeSort]

Clearly, an array is first allocated (tobeused as a scratch area) and thendeallocated after it is nolongerneeded.

It is also allowed for a function to allocatememory on its call-stack by calling a special functionalloca ,whichisgiventhefollowingtypeinATS:

(*

staload"libc/SATS/alloa.sats"

*)

funalloca

{dummy:addr}{n:int}(

pf:void@dummy|n:size_t(n)

):[l:addr](bytes(n)@l,bytes(n)@l->void@dummy|ptr(l))

Thetypeassignedto alloca makesitextremelyunlikelyforsomeonetounintentionallywritewell-typedcodeinATSthatmayerroneourlyattempttoaccessmemoryobtainedfromcalling alloca after

Page 329: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

thecallingfunctionhasreturned.

Thefollowingfunction array_ptr_alloca_tsz isthesameas alloca dynamicallybutitisgivenatypethatisoftenmoreconvenienttouse:

fun

array_ptr_alloca_tsz

{a:vt0p}{dummy:addr}{n:int}

(

pf:void@dummy|asz:size_t(n),tsz:sizeof_t(a)

):[l:addr](array(a?,n)@l,array(a?,n)@l->void@dummy|ptr(l))

As an example, the function template mergeSort implemented above can also be implemented asfollows:

implement

{a}(*tmp*)

mergeSort

(A,n,cmp)=let

valtsz=sizeof<a>

vardummy:void=()

prvalpf=view@dummy

val(

pfat,fpfat|p

)=array_ptr_alloca_tsz{a}(pf|n,tsz)

val((*void*))=msort1<a>(A,n,!p,cmp)

prval((*void*))=view@dummy:=fpfat(pfat)

in

//nothing

end//endof[mergeSort]

wherethearrayusedasascratchareaduringmerge-sortisallocatedonthecall-stackof mergeSort .Whilethisimplementationof mergeSort mayseeminteresting, it isactually inferior to thepreviousimplementationascalling alloca toallocatealargechunkofmemorycanreadilyleadtoacrashforwhich the cause is often very difficult to determine. In general, choosing alloca over malloc isdifficulttojustify,andanycalltotheformershouldbescrutinized.

Theentireimplementationofmerge-sortonarraysplussometestingcodeisavailableon-line.

Page 330: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:Array-BasedCircularBuffers

Array-basedcircularbuffersareofcommonuse inpractice.For instance, ina typicalclient/servermodel, a circular buffer can be employed to hold requests issued bymultiple clients that are thenprocessedbytheserveraccordingtothefirst-in-first-out(FIFO)policy.Inacasewhereeachrequestneeds to be given a priority (chosen from a fixed set), a circular buffer can be created for eachprioritytoholdrequestsofthatparticularpriority.

Let us declare a linear abstract type (that is, abstract viewtype) as follows for values representingcircularbuffers:

absvtype

cbufObj(a:vt@ype+,m:int,n:int)=ptr

Suchvaluesareconsideredsimplelinearobjects(asinheritanceisnotanissuetobedealtwithinthissetting).GivenaviewtypeVTandtwointegersMandN,theviewtype cbufObj(VT,M,N) isforagivenbufferofmaximalcapacityMthatcurrentlyholdsNelementsofthetypeVT.

Somepropertieson theparametersof cbufObj canbecapturedby introducing the followingprooffunction:

//

prfun

lemma_cbufObj_param

{a:vt0p}{m,n:int}

(buf:!cbufObj(a,m,n)):[m>=n;n>=0]void

//

Theinterfaceforthefollowingtwofunctiontemplatesindicatesthattheycanbecalledtocomputethecapacityandcurrentsizeofabuffer:

//

fun{a:vt0p}

cbufObj_get_cap

{m,n:int}(buf:!cbufObj(a,m,n)):size_t(m)

//

fun{a:vt0p}

cbufObj_get_size

{m,n:int}(buf:!cbufObj(a,m,n)):size_t(n)

//

While it is straightforward to use cbufObj_get_cap and cbufObj_get_size to tell whether a buffer is

Page 331: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

currentlyemptyorfull,adirectapproachislikelytobemoreefficient.Thefollowingtwofunctiontemplatescheckfortheemptinessandfullnessofagivencircularbuffer:

//

fun{a:vt0p}

cbufObj_is_empty

{m,n:int}(buf:!cbufObj(a,m,n)):bool(n==0)

//

fun{a:vt0p}

cbufObj_is_full

{m,n:int}(buf:!cbufObj(a,m,n)):bool(m==n)

//

Thefunctionsforcreatinganddestroyingcircularbuffersarenamed cbufObj_new and cbufObj_free ,respectively:

//

fun{a:vt0p}

cbufObj_new

{m:pos}(m:size_t(m)):cbufObj(a,m,0)

//

funcbufObj_free

{a:vt0p}{m:int}(buf:cbufObj(a,m,0)):void

//

Notethatabuffercanbefreedonlyifitcontainsnoelementsasanelement(ofsomeviewtype)maycontainresources.Ifelementsinabufferareofsome(non-linear)type,thenthefollowingfunctioncanbecalledtoclearoutalltheelementsstoredinthebuffer:

fun

cbufObj_clear

{a:t@ype}{m,n:int}

(buf:!cbufObj(a,m,n)>>cbufObj(a,m,0)):void

//endof[cbufObj_clear]

Thenext two functions are for inserting/removing an element into/fromagivenbuffer,which areprobablythemostfrequentlyusedoperationsonbuffers:

//

fun{a:vt0p}

cbufObj_insert

{m,n:int|n<m}

(

buf:!cbufObj(a,m,n)>>cbufObj(a,m,n+1),x:a

Page 332: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

):void//endof[cbufObj_insert]

//

fun{a:vt0p}

cbufObj_remove

{m,n:int|n>0}

(buf:!cbufObj(a,m,n)>>cbufObj(a,m,n-1)):(a)

//

Pleasefindon-linethefilecircbuf.satscontainingtheentiretyoftheinterfaceforfunctionscreating,destroyingandmanipulatingcircularbuffers.

Therearemanysimpleandpracticalwaysto implement theabstract type cbufObj and thefunctionsdeclaredincircbuf.sats.Inthefilecircbuf.dats,Igiveanimplementationthatemploysfourpointersp_beg,p_end,p_frstandp_last torepresentacircularbuffer:p_begandp_endare thestartingandfinishing addresses of the underline array, respectively, and p_frst and p_last are the startingaddressesoftheoccupiedandunoccupiedsegments(inthearray),respectively.Whatisspecialaboutthis implementationis itsemployingastyleofprogrammingthatdeliberatelyeschewstheneedforproof construction.While codewritten in this style is not guaranteed to be type-safe, the style cannonethelessbeofgreatpracticalvalueinasettingwhereconstructingformalproofsisdeemedtoocostlyarequirementtobefullyfulfilled.Anyonewhotriestogiveatype-safeimplementationforthefunctionsdeclaredincircbuf.satsshouldlikelyfindsomegenuineappreciationforthispoint.

Inthefilecircbuf2.dats,Igiveanotherimplementationinwhichacircularbufferisrepresentedasapointerp_begplus three integersm,n and f: p_begpoints to the starting locationof theunderlinearray,m is the size of the array (that is, the capacity of the buffer), n is the number of elementscurrently stored in thebuffer and f is the total numberof elements that have so far been removedfromthebuffer.Again,proofconstructionisdelibratelyeschewedinthisimplementation.

Page 333: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

LockingandUnlocking

In concurrent programming, the issue of safely locking and unlocking shared resources is bothessentialandchallenging.Iamtodemonstrateinthissectionconcretelyandconvincinglythatlineartypescanbeusedwithgreateffectivenesstoaddressthisissue.

Letusfirstintroducealinearabstracttype shared asfollows:

absvtypeshared(a:vtype)=ptr

Given a viewtypeVT (for some resources), a value of the type shared(VT) is essentially a boxedrecordcontaininga resourceof the typeVTplusa lock (or several)of somekind.The followingfunction shared_make iscalledtoturnaresourceintoasharedresource:

funshared_make{a:vtype}(x:a):shared(a)

Noticethatthetype shared(VT) itselfislinear.Intermsofimplementation,thereisusuallyareferencecount insidea linearsharedresource that isprotectedbyaspin-lock.Thefunctions shared_ref andshared_unref areforincreasinganddescreasingthereferencecountinsideasharedresource:

funshared_ref{a:vtype}(!shared(a)):shared(a)

funshared_unref{a:vtype}(shared(a)):Option_vt(a)

Ifthereferencecountofasharedresourceis1,thencalling shared_unref onthesharedresourcefreesthememoryusedinitsrepresentationandthenreturnstheresourcestoredinsideit.

The function shared_lock acquires the resource from a given shared resource and the functionshared_unlock doestheopposite:

//

absviewlocked_v

//

funshared_lock{a:vtype}(!shared(a)):(locked_v|a)

funshared_unlock{a:vtype}(locked_v|!shared(a),x:a):void

//

Note that the abstract view locked_v is introduced for linear proofs that are meant to remind theprogrammerthatasharedresoureneedstobereleasedafteritisacquired.

Ascanbeexpected,asharedresourcecanbeimplementedasaboxedtupleconsistingofaspin-lock,

Page 334: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

areferencecountandapointer(referringtothestoredresource):

//

datavtype

shared_(a:vtype)=

SHAREDof(spin1_vt(*lock*),int(*count*),ptr)

//

assumeshared=shared_

//

Note that the type spin1_vt is for linear spin-locks. The function shared_ref is implemented asfollows:

implement

shared_ref

{a}(sh)=let

//

val+@SHARED

(spin,count,_)=sh

//

val

spin=//fortemp.use

unsafe_spin_vt2t(spin)

//

val

(pf|())=spin_lock(spin)

valc0=count

val()=count:=c0+1

val((*void*))=spin_unlock(pf|spin)

prval((*void*))=fold@sh

//

in

$UN.castvwtp1{shared(a)}(sh)

end//endof[shared_ref]

Clearly,theimplementationmakesuseofseveralunsafecasts.Animplementationwithoutsuchcastswouldbehighlyinvolvedevenifitcouldbedone.Thespin-lockmustbeacquiredbeforethebindingbetween c0 andtheintegerstoredin count isformedforotherwisearaceconditioncanappear.Thefunction shared_unref isimplementedasfollows:

implement

shared_unref

{a}(sh)=let

//

Page 335: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

val+@SHARED

(spin,count,_)=sh

//

val

spin=//fortemp.use

unsafe_spin_vt2t(spin)

//

val

(pf|())=spin_lock(spin)

valc0=count

val()=count:=c0-1

val((*void*))=spin_unlock(pf|spin)

prval((*void*))=fold@sh

//

in

//

if

c0<=1

thenlet

val+~SHARED(spin,_,x)=sh

val((*freed*))=spin_vt_destroy(spin)

in

Some_vt($UN.castvwtp0{a}(x))

end//endof[then]

elselet

prval()=$UN.cast2void(sh)inNone_vt()

end//endof[else]

//

end//endof[shared_unref]

In the casewhere the reference count is 1, then the shared resource is freed, the spin-lock in it isdestroyed,andtheresourceinitisreturned.

Thefunctions shared_lock and shared_unlock areimplementedasfollows:

implement

shared_lock

{a}(sh)=let

//

val+@SHARED(spin,_,x)=sh

//

val

spin=

unsafe_spin_vt2t(spin)

//

val

Page 336: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

(pf|())=spin_lock(spin)

//

valx0=$UN.castvwtp0{a}(x)

//

prval()=fold@sh

//

in

($UN.castview0(pf)|x0)

end//endof[shared_lock]

implement

shared_unlock

{a}(pf|sh,x0)=let

//

val+@SHARED(spin,_,x)=sh

//

val

spin=

unsafe_spin_vt2t(spin)

//

val()=x:=$UN.castvwtp0{ptr}(x0)

//

val()=

spin_unlock($UN.castview0(pf)|spin)

//

prval()=fold@sh

//

in

//nothing

end//endof[shared_unlock]

Inthecaseof shared_lock ,pleasenoticethatthecontentstoredinthevariable x isreadoutafterthespin-lockisacquired.Thisiscrucialforotherwisearaceconditioncanreadilyappear.Inthecaseofshared_unlock ,thecontentofthevariable x isupdatedbeforetheacquiredspin-lockisreleased.

Pleasefindon-linethefileshared_vt.datscontainingtheentiretyofthecodepresentedinthissection.Inaddition,thefilealsocontainsanimplementationofthreethreadsthatmoveinlockedsteps:thread0moves;thread1moves;thread2moves;thread0moves;thread1moves;thread2moves;etc.

Page 337: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

LinearChannelsforAsynchronousIPC

In this section, I will present an implementation of linear channels to support asynchronouscommunicationbetweenthreads.ThisisalsoaveryfittingoccasionformetoadvocatewhatIoftenrefertoasprogrammer-centricprogramverification.

Acommunicationchannelbetweenthreadsisessentiallyaqueuewrappedinsomekindofprotectionmechanismneededforguardingagainstraceconditions.Assumethataqueueisofafixedcapacity,thatis,thecapacityofthequeueisfixedafteritscreation.Ifthequeueisfull,theninsertinganelementintoitresultsinafailure.Ifthequeueisempty,thenremovinganelementfromitresultsinafailure.In order to prevent inserting into a full queue or removing from an empty queue, I could firstintroducealinearabstracttypeforqueuesasfollows:

absvtype

queue_vtype(a:vt@ype+,int(*m*),int(*n*))

vtypedefqueue(a:vt@ype,m:int,n:int)=queue_vtype(a,m,n)

wherethetype queue(VT,M,N) isforaqueueofcapacityMthatcurrentlycontainsNelementsoftypeVT.Then the functions for inserting intoand removing fromaqueueareexpected tobegiven thefollowinginterface:

//

fun{a:vt0p}

queue_insert

{m,n:nat|m>n}

(!queue(a,m,n)>>queue(a,m,n+1),a):void

//

fun{a:vt0p}

queue_remove

{m,n:nat|n>0}(!queue(a,m,n)>>queue(a,m,n-1)):(a)

//

The presented abstract type queue can indeedwork verywell for the task of implementing linearchannels.However,Iwillnotcontinuewiththisversionof queue furtherforIintendtopresentastyleofprogramverificationthatislessrigorousbutfarmoreflexible.

Followingisanotherversionofabstracttype queue :

//

absvtype

queue_vtype(a:vt@ype+,int(*id*))=ptr

Page 338: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

//

vtypedef

queue(a:vt0p,id:int)=queue_vtype(a,id)

vtypedefqueue(a:vt0p)=[id:int]queue(a,id)

//

GivenaviewtypeVTandanintegerID, queue(VT,ID) isforaqueuecontainingelementsofthetypeVTthatcanbeuniquelyidentifiedwiththeintegerID.SoonemaythinkofIDassomeformofstamp.Thefollowingdeclaredfunction queue_isnil isfortestingwhetheragivenqueueisempty:

//

abspropISNIL(id:int,b:bool)

//

fun

{a:vt0p}

queue_isnil{id:int}(!queue(a,id)):[b:bool](ISNIL(id,b)|bool(b))

//

Given an integer ID, a proof of the prop ISNIL(ID,true) ( ISNIL(ID,false) ) means that the queueuniquelyidentifiedbyIDis(not)empty.Similarly,thefollowingdeclaredfunction queue_isful isfortestingwhetheragivenqueueisfull:

//

abspropISFUL(id:int,b:bool)

//

fun

{a:vt0p}

queue_isful{id:int}(!queue(a,id)):[b:bool](ISFUL(id,b)|bool(b))

//

Given an integer ID, a proof of the prop ISFUL(ID,true) ( ISFUL(ID,false) ) means that the queueuniquelyidentifiedbyIDis(not)full.

Thefunctions queue_insert and queue_remove forinsertingintoandremovingfromagivenqueuecannowbegiventhefollowinginterface:

//

extern

fun

{a:vt0p}

queue_insert

{id:int}

(

Page 339: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

ISFUL(id,false)

|xs:!queue(a,id)>>queue(a,id2),x:a

):#[id2:int]void

//

extern

fun

{a:vt0p}

queue_remove

{id:int}

(

ISNIL(id,false)|xs:!queue(a,id)>>queue(a,id2)

):#[id2:int]a//end-of-fun

//

Notethateitherinsertinganelementintoaqueueorremovinganelementfromaqueueassignsanewstamptothequeue.Thisisessentialforinterpreting ISNIL and ISFUL inthemannerpresentedabove.

Inordertocall queue_insert onagivenqueue,oneneedstohaveaproofattestingtothequeuebeingnotfull.Suchaproofisobtainedifcalling queue_isful onthequeuereturnsfalse.Similarly,inordertocall queue_remove onagivenqueue,onecanfirstcall queue_isnil on thequeue toobtainaproofattestingtothequeuebeingnotempty.

What is really of concern here is not to actually verify that queue_isnil and queue_isful have theinterfaceassignedtothem.Instead,thefocusisonensuringthat queue_insert isneverappliedtoafullqueueand queue_remove isneverappliedtoanemptyqueueundertheassumptionthat queue_isnil andqueue_isful have the assigned interface. I refer to this form of program verification as beingprogrammer-centric because its correctness is not formally established in an objective manner. Imyselffindthatprogrammer-centricprogrammverificationisveryflexibleandeffectiveinpractice.Ifwebelievethatconstructinginformalmathematicalproofscanhelponecheckwhethertheprovenstatementsarevalid,thenitisonlynaturaltobelievethatprogrammer-centricprogramverificationcanalsohelponecheckwhetherverifiedprogramsarecorrect.

Let us now start to implement linear channels for asynchronous communication between threads.First,letusdeclarealinearabstracttype channel asfollows:

absvtypechannel_vtype(a:vt@ype+)=ptr

vtypedefchannel(a:vt0p)=channel_vtype(a)

Thefunctionforinsertinganelementintoachannelisgiventhefollowinginterface:

fun{a:vt0p}channel_insert(!channel(a),a):void

Page 340: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Thecallerof channel_insert isblockedifthechannelisfull.Similarly,thefunctionforremovinganelementfromachannelisgiventhefollowinginterface:

fun{a:vt0p}channel_remove(chan:!channel(a)):(a)

Thecallerof channel_remove isblockedifthechannelisempty.

Letachannelberepresentedasfollows:

//

datavtype

channel_=

{

l0,l1,l2,l3:agz

}CHANNELof

@{

cap=intGt(0)

,spin=spin_vt(l0)

,rfcnt=intGt(0)

,mutex=mutex_vt(l1)

,CVisnil=condvar_vt(l2)

,CVisful=condvar_vt(l3)

,queue=ptr//deqarray

}(*endof[channel]*)

//

assumechannel_vtype(a:vt0p)=channel_

//

Thereare7fieldsintherecordrepresentingachannel;the cap fieldstoresanintegerindicatingthe(fixed)capacityofthechannel;the spin fieldstoresaspin-lockforprotectingthereferencecountinthefieldofthename rfcnt ;the mutex fieldstoresamutexforprotectingthequeueinthefieldofthename queue ;thefield CVisnil storesaconditionalvariableforthesituationwhereacaller(holdingthemutex)wantstowaitfortheconditionthatthequeuebecomesnotempty;thefield CVisful storesaconditional variable for the situation where a caller (holding the mutex) wants to wait for theconditionthatthequeuebecomesnotfull.

Thefunction channel_insert isgiventhefollowingimplementation:

implement

{a}(*tmp*)

channel_insert

(chan,x0)=let

//

Page 341: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

val+CHANNEL

{l0,l1,l2,l3}(ch)=chan

valmutex=unsafe_mutex_vt2t(ch.mutex)

val(pfmut|())=mutex_lock(mutex)

valxs=

$UN.castvwtp0{queue(a)}((pfmut|ch.queue))

val((*void*))=channel_insert2<a>(chan,xs,x0)

prvalpfmut=$UN.castview0{locked_v(l1)}(xs)

val((*void*))=mutex_unlock(pfmut|mutex)

//

in

//nothing

end//endof[channel_insert]

wheretheauxiliaryfunction channel_insert2 isgiventhefollowinginterface:

fun{a:vt0p}

channel_insert2

(!channel(a),!queue(a)>>_,a):void

Please note that channel_insert2 is called when the caller is holding themutex inside the channel.Followingisanimplementationfor channel_insert2 :

implement

{a}(*tmp*)

channel_insert2

(chan,xs,x0)=let

//

val+CHANNEL

{l0,l1,l2,l3}(ch)=chan

//

val(pf|isful)=queue_isful(xs)

//

in

//

if

isful

thenlet

prval

(pfmut,fpf)=

__assert()where

{

extern

praxi__assert():vtakeout0(locked_v(l1))

}

Page 342: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

valmutex=unsafe_mutex_vt2t(ch.mutex)

valCVisful=unsafe_condvar_vt2t(ch.CVisful)

val((*void*))=condvar_wait(pfmut|CVisful,mutex)

prval((*void*))=fpf(pfmut)

in

channel_insert2(chan,xs,x0)

end//endof[then]

elselet

valisnil=queue_isnil(xs)

val((*void*))=queue_insert(pf|xs,x0)

val((*void*))=

ifisnil.1

thencondvar_broadcast(unsafe_condvar_vt2t(ch.CVisnil))

//endof[if]

in

//nothing

end//endof[else]

//

end//endof[channel_insert2]

Thelogicbehind channel_insert2 canbeexplainedasfollows.Ifthequeueinthegivenchannelisfull,thecallercalls condvar_wait to release themutex it holds and thenwaiton the conditionalvariablestoredinthefield CVisful ofthechannel;afterthecallerregainsthemutexafterbeingawokenbyasignalsent to theconditioanlvariable, itcalls channel_insert2 recursively. If thequeue in thegivenchannelisnotfull,thenthecallerinsertagivenelementintothequeuestoredinthefield queue andthen returns.Note that channel_insert2 is a tail-recursive function that essentially corresponds to astandardwhile-loopoftenappearinginCcodeforhandlingthewaitonaconditionalvariable.

Byfollowingtheaboveimplementationfor channel_insert (and channel_insert2 ),itshouldbeprettystraightforwardforonetofigureoutanimplementationfor channel_remove .Ileaveitasanexercise.

Please find on-line the file channel_vt.dats containing the entirety of the code presented in thissectionplussomecodefortesting.

Page 343: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

V.ProgrammingwithFunctionTemplatesTableofContents17.FromGenericitytoLate-Binding

Page 344: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 345: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes
Page 346: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Chapter17.FromGenericitytoLate-BindingThesupportforfunctiontemplates inATSisdeeply ingrainedin thedesignandimplementationofATS.Primarily,functiontemplatesaremeanttoprovideageneralapproachtocodereuseinATSthatishighlyflexible(intermsofapplicability)whileincurringminimalrun-timeoverheadifany.BothATSPRE (that is, ATSLIB/prelude) and ATSLIB/libats are nearly entirely template-based, and thetemplates in these libraries are for use by atsopt to generate C code that implements templateinstancesintheATSsourcebeingcompiled.ThelibraryfilesofATSforlinking(libatslib.aand

libatslib.so) are minimal, and they are not even necessary for compiling ATS source into

executablebinaries.

Thecodeemployedforillustrationinthischapterplussomeadditionalcodefortestingisavailableon-line.

Page 347: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

GenericityofTemplateImplementations

AsisbrieflyexplainedinPartIofthebook,functiontemplatescanbeseenasanaturalsolutiontotheproblemofsupportingparametricpolymorphismin thepresenceofnativeunboxeddata.However,functiontemplatescandomuchmorethanjustsupportingparametricpolymorphism.Let myprint beafunctiontemplateofthefollowinginterface:

fun{a:t@ype}myprint(x:a):void

Given a value, myprint is supposed to print out some kind of representation for this value. Forexample,wecanimplement myprint asfollows:

implement{a}myprint(x)=print_string"?"

Thisimplementationof myprint isoftenreferredtoasa(fully)generictemplateimplementationduetonorestrictionbeingimposedonthetemplateparameter.Followingisanotherwaytocodethesameimplementation:

implement(a)myprint<a>(x)=print_string"?"

Clearly, the above generic implementation of myprint is unsatisfactory as it outputs no specificinformationonagivenvalue.Wemaywanttoimplement myprint asfollowsforonlyvaluesofthetype int :

implementmyprint<int>(x)=print_int(x)

where print_int is called to print out a given integer. This implementation of myprint is oftenreferred to as a specific template implementation due to the template parameter being bound to aspecifictype(thatis, int inthiscase).Thefollowingcodeimplements myprint forlist-values(thatis,valuesoftype List(T) forsometypeT):

implement(a)

myprint<List(a)>(xs)=

case+xsof

|list_nil()=>()

|list_cons(x,xs)=>

(myprint<a>(x);myprint<List(a)>(xs))

Thisimplementationof myprint isoftenreferredtoasapartiallygenerictemplateimplementation.In

Page 348: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

orderforaninstanceof myprint tousethisimplementation,thetemplateparameterfortheinstancemustbeoftheform List(T) forsometypeT.Asanexample,thefollowingcodecallsaninstanceofmyprint toprintoutalistoftwointegerlists:

(*

**Theoutputis"0123401234"

*)

valys=$list{int}(0,1,2,3,4)

valyss=$list{List(int)}(ys,ys)

val((*void*))=myprint<List(List(int))>(yss)

val((*void*))=print_newline((*void*))

Implementations of a function template can be ordered according to an obvious partial orderingreferredtoasgenericityordering:Thegenericityofoneimplementationislessthanorequaltothatofanotheroneiftheformerimplementationisaninstanceofthelatterone.Pleasenotethatthefirst-fit (instead of best-fit) strategy is employed to locate the template implementation needed forcompiling a given template instance.More specifically, locating the template implementation for aparticular template instance follows thestandardprincipleof lexical scoping tosearch for the firstonethatisavailableforuse.

In practice, there is quite a bit of subtlety in locating a template implementation for a templateinstance.Let myprint2 beafunctiontemplateofthefollowinginterface:

fun{a:t@ype}myprint2(x:a):int

Followingisapartiallygenericimplementationof myprint2 :

//

implement(a)

myprint2<List(a)>(xs)=

case+xsof

|list_nil()=>()

|list_cons(x,xs)=>

(myprint<a>(x);1+myprint2(xs))

//

Thistemplateimplementationactuallybehavesverydifferentlyfromwhatonemighthaveexpected.Notethatthetemplateparameterofthecalledinstanceof myprint2 inthebodyoftheimplementationissynthesizedtobeatypeof theform list(a,N) forsomestatic termN(of thesort int ).As thisformcannevermatch List(T) foranytypeT,thecalledinstanceofthetemplate myprint2 cannotbe

Page 349: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

compiledaccordingtothegiventemplateimplementationof myprint2 .Thisissuecanbereadilyfixedbypassingexplicitythetype List(a) (asatemplateparameter)tothecalledinstanceof myprint2 :

//

implement(a)

myprint2<List(a)>(xs)=

case+xsof

|list_nil()=>()

|list_cons(x,xs)=>

(myprint<a>(x);1+myprint2<List(a)>(xs))

//

Theinstance myprint2<List(a)> inthisexampleisoftenreferredtoasarecursiveinstance.Ingeneral,it is a goodprogrammingpractice toavoid using recursive instances. For example, the followingequivalentimplementationof myprint2 makesnouseofrecursiveinstances:

//

implement(a)

myprint2<List(a)>

(xs)=let

//

fun

aux

(xs:List(a)):int=

//

case+xsof

|list_nil()=>0

|list_cons(x,xs)=>(myprint<a>(x);1+aux(xs))

//

in

aux(xs)

end//endof[myprint2<List(a)>]

//

Pleasefindon-linethefilemyprint.datscontainingtheentiretyofthecodepresentedinthissectionplussometestingcode.

Page 350: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:GenericOperationsonNumbers

There are many types of numbers in ATS.With function templates, we can greatly enhance codesharing in numerical computation. For example, we can give a generic implementation ofmatrixmultiplicationofthefollowinginterface:

fun

{a:t@ype}

matrix_mul

{p,q,r:int}

(

p:int(p)

,q:int(q)

,r:int(r)

,A:&matrix(a,p,q)

,B:&matrix(a,q,r)

,C:&matrix(a?,p,r)>>matrix(a,p,r)

):void//endof[matrix_mul]

and then use it to immediately obtain implementations of matrix multiplication for matrices ofintegers,matricesoffloatingpointnumbers,matricesoffloatingpointcomplexnumbers,etc.Thisapproachisclearlyfarsuperiortorelyingonerror-pronemacrosinC.

Letus take a lookat a concrete example involvinggenericoperationsonnumbers.The followingcodegivesastandardimplementationofthefactorialfunction:

//

extern

funfact(n:int):int

//

implement

fact(n)=

ifn>0thenn*fact(n-1)else1

//endof[fact]

//

Whenappliedto100, fact islikelytoreturn0.Thiscanbeeasilyunderstoodasthetruevalueofthefactorialof100 isamultipleof232and themultiplicationoperationon integersof the type int isprobablymodulo232.Supposethatwewanttoreplacethismultiplicationoperationwiththeoneonfloating point numbers of double precision.This can be done by implementing a slight variant offact asfollows

Page 351: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

//

extern

funfactd(n:int):double

implement

factd(n)=

ifn>0thenn*factd(n-1)else1.0

//endof[factd]

//

Whenappliedto100, factd shouldreturnalargefloatingpointnumber.Obviously,thereisagreatdealofcodeduplicationbetween the implementationsof fact and factd .Wecan readilyeliminatethisduplicationbyintroducingagenericimplementationofthefactorialfunctionasfollows:

//

extern

fun{a:t@ype}gfact(n:int):a

//

implement

{a}(*tmp*)

gfact(n)=(

//

ifn>0

thengmul_int_val<a>(n,gfact<a>(n-1))

elsegnumber_int<a>(1)

//

)(*endof[gfact]*)

//

WithabitofhelpfromthesupportforoverloadinginATS,wecanrewrite gfact asfollows:

implement

{a}(*tmp*)

gfact(n)=let

//

overload*withgmul_int_val

//

in

//

ifn>0

thenn*gfact<a>(n-1)elsegnumber_int<a>(1)

//

end(*endof[gfact]*)

Wecannowimplement fact and factd asfollows:

Page 352: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

//

implementfact(n)=gfact<int>(n)

implementfactd(n)=gfact<double>(n)

//

There is support in ATS based on the GNU multiple precision arithmetic library (GMPLIB) forintegersofunlimitedprecision.Thefollowingcodepresentsawaytocomputethetruevalueofthefactorialof100:

//

staload_(*T*)=

"{$LIBATSHWXI}/intinf/DATS/intinf_t.dats"

staload_(*VT*)=

"{$LIBATSHWXI}/intinf/DATS/intinf_vt.dats"

//

staloadGINTINF=

"{$LIBATSHWXI}/intinf/DATS/gintinf_t.dats"

//

typedefintinf=$GINTINF.intinf

overloadprintwith$GINTINF.print_intinf

//

val()=

println!("gfact<intinf>(100)=",gfact<intinf>(100))

//

Ionlylistsomeleadingdigitsoftheresult:

gfact<intinf>(100)=933262154439441526816992388562667[...omitted...]

Pleasefindon-linethefilegnumber.datscontainingtheentiretyofthecodepresentedinthissectionplussometestingcode.

Page 353: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

TemplatesasaSpecialFormofFunctors

Many uses of higher-order functions can be readily replaced with function templates in ATS. Inparticular,higher-orderfunctionsareoftenimplementedinATSbasedonthecorrespondingfunctiontemplates. Let us start with a concrete example. Following is a standard implementation of listmappingasahigher-orderfunction(template):

//

extern

fun

{a:t@ype}

{b:t@ype}

list_map_fun{n:nat}

(xs:list(a,n),f:a->b):list_vt(b,n)

//

implement

{a}{b}

list_map_fun(xs,f)=let

//

fun

aux{n:nat}

(xs:list(a,n)):list_vt(b,n)=

(

case+xsof

|list_nil()=>list_vt_nil()

|list_cons(x,xs)=>list_vt_cons(f(x),aux(xs))

)

//

in

aux(xs)

end//endof[list_map_fun]

//

Givenalistofcerntainlengthandafunction(whichisenvless), list_map_fun returnsalinearlistofthe same length.Unfortunately, list_map_fun cannot be called on a list and a closure-function.Wecertainlycanimplementavariantof list_map_fun ofthefollowinginterfacebyessentiallyduplicatingtheimplementationof list_map_fun :

//

extern

fun

{a:t@ype}

{b:t@ype}

Page 354: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

list_map_cloref{n:nat}

(xs:list(a,n),f:a-<cloref1>b):list_vt(b,n)

//

While list_map_cloref can be called on a list and a closure-function, the closure-function that isformed at run-time to be passed to a call to list_map_cloref most likely becomes garbageimmediately after the call returns. Without garbage collection (GC), the memory for storing theclosureisleaked.Wesurelyhavemanygoodreasonsforavoidingusingahigher-orderfunctionlikelist_map_cloref whendoingembeddedprogramminginATS.

Aproperwaytoimplementlistmapping(asIseeit)isgivenasfollows:

//

extern

fun

{a:t@ype}

{b:t@ype}

list_map{n:nat}

(xs:list(a,n)):list_vt(b,n)

//

extern

fun

{a:t@ype}{b:t@ype}list_map$fopr(x:a):b

//

implement

{a}{b}

list_map(xs)=let

//

fun

aux{n:nat}

(xs:list(a,n)):list_vt(b,n)=

(

case+xsof

|list_nil()=>list_vt_nil()

|list_cons(x,xs)=>list_vt_cons(list_map$fopr<a><b>(x),aux(xs))

)(*endof[aux]*)

//

in

aux(xs)

end//endof[list_map]

//

The function template list_map is given in a style that is often referred to as being functorial:list_map canbethoughtofasafunctorinStandardMLthatappliestoamoduleconsistingofasingle

Page 355: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

function list_map$fopr . In SML, each argument of a functor,which itself is amodule, needs to beconstructedandthenpassedtothefunctorexplcitly.InATS,thetemplateimplementationneededforcompiling a particular template instance is located through a search procedure (that follows thestandardprincipleoflexicalscoping).

With list_map , we can implement both list_map_fun and list_map_cloref as follows in astraightforwardmanner:

implement

{a}{b}

list_map_fun(xs,f)=let

//

implementlist_map$fopr<a><b>(x)=f(x)

//

in

list_map<a><b>(xs)

end//endof[list_map_fun]

(**************)

implement

{a}{b}

list_map_cloref(xs,f)=let

//

implementlist_map$fopr<a><b>(x)=f(x)

//

in

list_map<a><b>(xs)

end//endof[list_map_cloref]

For those who are familiar with functors in SML, the implementation of list_map_fun andlist_map_cloref shouldclearlyremindthemoffunctorapplication.

Pleasefindon-linethefilelist_map.datscontainingtheentiretyofthecodepresentedinthissectionplussometestingcode.

Page 356: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Example:TemplatesforLoopConstruction

Beginners in functional programming (FP) who have already acquired some knowledge ofimperative programming often ask about ways to construct for-loops and while-loops in FP. AcommonlygivenansweristhatloopconstructsareunnecessaryinFPastheycanbereadilyreplacedwithhigher-orderfunctions.Letusfirstseesomethornyissueswiththisanswer.

The followingcode inC implementsa function that returns the sumof the firstnnaturalnumberswhenappliedtoanaturalnumbern:

int

tally(intn){

inti,res;

for(i=0,res=0;i<n;i+=1)res+=i;

returnres;

}

Thisfunction tally canbegiventhefollowingequivalentimplementationinATS:

fun

tally

(

n:int

):int=loop(0,0)where

{

funloop(i:int,res:int):int=

ifi<nthenloop(i+1,res+i)elseres

}

wherethetail-recursivefunction loop isjustatranslationofthefor-loopinC.

When someone claims that loop constructs canbe replacedwithhigher-order functions, heor sheprobablymeanstoconstructloopswithafunctionlikethefollowingone:

fun

for_loop

(

count:int,limit:int,fwork:(int)-<cloref1>void

):void=(

ifcount<limit

then(fwork(count);for_loop(count+1,limit,fwork))else()

//endof[if]

)(*endof[for_loop]*)

Page 357: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Forexample,thefollowingfunction tally2 isdirectlybasedon for_loop :

fun

tally2

(

n:int

):int=let

valres=ref<int>(0)

in

for_loop(0,n,lam(i)=>!res:=!res+i);!res

end//endof[tally2]

While both tally and tally2 return the same resultwhen applied to a given natural number, theybehaveverydifferentlyatrun-time.Inparticular,eachcallto tally2 createsa(persistent)referenceon heap for temporary use; the reference becomes garbage immediately after the call returns.Comparedto tally , tally2 isinefficientbothtime-wiseandmemory-wise.

Toeliminatetheneedforreferencecreationin tally2 ,weturn for_loop intothefollowingfunctiontemplate for_loop2 :

fun{

env:t@ype

}for_loop2

(

count:int,limit:int

,env:&env>>_,fwork:(int,&env>>_)-<cloref1>void

):void=(

if

count<limit

then(

fwork(count,env);for_loop2<env>(count+1,limit,env,fwork)

)else()

//endof[if]

)(*endof[for_loop2]*)

Wecanfurtherturn tally2 intothefollowing tally3 basedon for_loop2 :

fun

tally3

(

n:int

):int=let

varres:int=0

in

Page 358: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

for_loop2<int>(0,n,res,lam(i,res)=>res:=res+i);res

end//endof[tally3]

While tally3 improves upon tally2 , it is still a bit unsatisfactory. Clearly, the closure functionformed before tally3 calls for_loop2 becomes garbage immediately after the call returns. It isplausible to expect that an optimizingC compiler (e.g., gcc and clang) can eliminate the need foractualclosureformationwhenitcompilesontheCcodegeneratedfromATSsource,butthereisnoguarantee. Inorder tohave such aguarantee,we can evolve for_loop2 into the following functiontemplate for_loop3:

fun{

env:t@ype

}for_loop3

(

count:int,limit:int,env:&env>>_

):void=(

if

count<limit

then(

for_loop3$fwork<env>(count,env);for_loop3<env>(count+1,limit,env)

)else()

//endof[if]

)(*endof[for_loop3]*)

where for_loop3$fwork isgiventheinterfacebelow:

fun{

env:t@ype

}for_loop3$fwork(count:int,env:&env>>_):void

Finally,wecanturn tally3 into tally4 asfollows:

fun

tally4

(

n:int

):int=let

//

varres:int=0

//

implement

for_loop3$fwork<int>(i,res)=res:=res+i

//

in

Page 359: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

for_loop3<int>(0,n,res);res

end//endof[tally4]

ByinspectingtheCcodegeneratedbyatsoptfromcompiling tally4 ,wecanseethattheCcodeisessentiallyequivalenttotheimplementationof tally inC(givenatthebeginningofthissection).

By now, the reader probably agrees with me if I say the statement should at least be consideredgrossly inaccurate that claims loop constructs in FP can be readily replaced with higher-orderfunctions.Pleasefindon-line thefile loopcons.dats containing theentiretyof thecodepresented inthissectionplussometestingcode.

Page 360: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

Template-BasedSupportforLate-Binding

Whenaskedaboutthemeaningofobject-orientedprogramming(OOP),AlanKayoncesaidthatOOPtohimmeantonlymessaging,localretentionandprotectionandhidingofstate-process,andextremelate-bindingofallthings.

In ATS, function templates can provide a highly flexible approach to supporting late-binding (offunction calls). Let us first take a look at a simple example to see why late-binding can be sodesirable.Thefollowingcodedeclaresadatatype intfloat suchthateachvalueofthisdeclaredtyperepresentseitheranintegerorafloatingpointnumber(ofdoubleprecision):

//

datatype

intfloat=

INTofint|FLOATofdouble

//

Inordertoprintvaluesofthetype intfloat ,wecanimplement print_intfloat asfollows:

//

fun

print_intfloat

(x:intfloat):void=

(

case+xof

|INT(int)=>print_int(int)

|FLOAT(float)=>print_double(float)

)

//

where print_int and print_double aremonomorphicfunctionsforprintinganintegerandafloatingpoint number (of double precision), respectively.There are certainlymany differentways to printintegersandfloatingpointnumbers,but print_intfloat onlyusesaparticularonefor integers (viaprint_int ) and a particular one for floating point numbers (via print_double ). One possibility ofavoiding this form of extreme inflexibility is to define a higher-order function fprint_intfloat asfollows:

//

fun

fprint_intfloat

(

Page 361: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

x:intfloat

,print_int:int->void

,print_double:double->void

):void=

(

case+xof

|INT(int)=>print_int(int)

|FLOAT(float)=>print_double(float)

)

//

With fprint_intfloat ,onecandecidetochooseimplementationsfor print_int and print_double atalater stage. In this regard, I say that higher-order functions can support a form of late-binding.However,usinghigher-orderfunctionsinsuchamannerisnotwithoutseriousproblems.Basically,anyfunctionthatcalls print_int eitherdirectlyor indirectlyneeds tobe turnedintoahigher-orderfunction,andthesameappliestofunctionscalling print_double aswell.Thisstyleofprogrammingwithextensiveuseofhigher-orderfunctionscansoonbecomeextremelyunwieldywhenthenumberoffunctionsgrowslargethatneedtobetreatedlike print_int and print_double .

Insteadofusinghigher-orderfunctions,wecanrelyontemplatefunctionstosupportlate-binding(offunctioncalls).Forexample,thefollowingcodeimplementsatemplatefunction tprint_intfloat forprintingvaluesofthetype intfloat :

//

extern

fun{}

tprint_int(int):void

extern

fun{}

tprint_double(double):void

extern

fun{}

tprint_intfloat(intfloat):void

//

(**************)

//

implement

tprint_int<>(x)=print_int(x)

implement

tprint_double<>(x)=print_double(x)

//

(**************)

//

Page 362: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

implement

tprint_intfloat<>(x)=

(

case+xof

|INT(int)=>tprint_int<>(int)

|FLOAT(float)=>tprint_double<>(float)

)

//

Pleasenotethatthedefaultimplementationsfor tprint_int and tprint_double arebasedon print_intand print_double ,respectively.Ascanbeexpected,thefollowingcodeoutputstwolines:

//

val()=(

tprint_intfloat<>(INT(0));print_newline()

)(*endof[val]*)

//

val()=(

tprint_intfloat<>(FLOAT(1.0));print_newline()

)(*endof[val]*)

//

wherethefirstlineconsistsofthestring"0"andthesecondonethestring"1.000000".Thefollowingcodealsooutputstwolines:

local

//

implement

tprint_int<>(x)=print!("INT(",x,")")

implement

tprint_double<>(x)=print!("FLOAT(",x,")")

//

in(*in-of-local*)

//

val()=(

tprint_intfloat<>(INT(0));print_newline()

)(*endof[val]*)

//

val()=(

tprint_intfloat<>(FLOAT(1.0));print_newline()

)(*endof[val]*)

//

end//endof[local]

wherethefirstlineconsistsofthestring"INT(0)"andthesecondonethestring"FLOAT(1.000000)").

Page 363: Introduction to Programming in ATSats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/... · Parametric Polymorphism Function Templates Polymorphic Functions Polymorphic Datatypes

In the latter case, the calls to template instances tprint_int<> and tprint_double<> are compiledaccording to the implementations for tprint_int and tprint_double given between the keywordslocal and in .

Pleasefindon-linethefile intfloat.datscontaining theentiretyof thecodepresented in thissectionplussometestingcode.

Done.