introduction to dependent types in agda
Post on 10-Nov-2015
38 Views
Preview:
DESCRIPTION
TRANSCRIPT
-
Brutal[Meta]IntroductiontoDependentTypesinAgdaFebruary,04201300:00March,14201301:22tags: fp(/note/tag/fp/) agda(/note/tag/agda/) dependenttypes(/note/tag/dependenttypes/) logic(/note/tag/logic/)
IntroductiontointroductionAgdadoesnt lack tutorialsand introductions, there isawholepageof themon theAgdawiki [1] (forageneraldocumentationlistsee[2]).Personally,Irecommend:
AntonSetzersintroduction(worksespeciallyverywellforthosewithalogicalbackground,butiseasyenoughtofollowforeveryoneelsetoo)[3]AnaBovesandPeterDybjersintroduction[4].UlfNorellsintroductionforfunctionalprogrammers[5].ThorstenAltenkirchslectures[6].
(Thislistisnotanorder,thebestpracticeistoreadthem(andthispage)simultaneously.Bytheway,thisdocumentisfarfromfinished,butshouldbeprettyusefulinitscurrentstate.)
SamepropositionholdsforCoq[7],Idris[8]and,toalesserextent,forEpigram[9].
Forageneralintroductiontotypetheoryfieldlooknofurtherthan:
MortenHeineB.SrensensandPawelUrzyczynslectures[10].SimonThompsonsbook[11].
Theresalsoanumberoftheoreticalbooksstronglyrelatedtothelanguageslistedabove:
ThenotesofPerMartinLfs(theauthorofthecoretypetheoryusedbyallofAgda,Coq,IdrisandEpigram)lectures[12],[13].AbitmorepracticalorientedbookbyBengtNordstrmetal[14].
Andanumberoftutorialswhichshowhowtoimplementadependentlytypedlanguageyourself:
SimplerEasier[15].AtutorialbyAndrejBauer[16][18].
Theresalottoreadalready,whyanotherintroduction?Becausethereisagap.Theoryishugeandfullofsubtledetailsthataremostly ignoredintutorial implementationsandhiddeninlanguagetutorials(sothatunpreparedarenotscaredaway).Whichishardlysurprisingsincethecurrentstateofarttakesyearstoimplementcorrectly,andeventhensome(considerable)problemsremain.
Nevertheless,Ithinkitisthehardpartsthatmatter,andIalwayswantedatutorialthatatleastmentionedtheir existence (well, obviously there is a set of dependently typed problemsmost people appreciate,e.g.undecidabletypeinference,butthereisstillalotofissuesthatarenotsowellunderstood).Moreover,
about(/) activity(/activity/) notes(/note/)
-
after Istumbleduponsomeof these lesserknownpartsofdependently typedprogramming Istarted tosuspect thathiding thembehind the languagegoodnessesactuallymakes thingsharder to understand.DottedpatternsandunificationstuckerrorinAgdaareperfectexamples.Iclaimthat:
Peoplefindithardtounderstanddottedpatternsexactlybecauseitshardtoexplainthemabovethelanguageabstractionlevel.Explicitaccesstounificationengineisausefulinteractiveprogramconstructiontool.IdidadozenofproofsIprobablycouldntdootherwisebyunifyingexpressionsbyhand.AsfarasImaware,noproofcheckerautomatesthisinausablewayyet.Thereisaproposal(http://code.google.com/p/agda/issues/detail?id=771)withmyimplementationideasfor agda2mode .
Havingsaidthat,thisarticleservessomewhatcontroversialpurposes:
ItisaintroductiontoAgda,startingasaverybasicone,writtenforthosewithhalfwaythroughundergradcourse(readbasic)discretemath,numbertheory,settheoryandHaskellbackground.Iactuallytaughtthistoundergradstudents[19]anditworks.ButitaimsnottoteachAgda,buttoshowhowdependentlytypedlanguagesworkbehindthesceneswithoutactuallygoingbehindthescenes(because,asnotedabove,goingbehindthescenestakesyears).ImprettysureitispossibletowriteaverysimilarintroductiontoCoq,Idris,Epigramorwhatever,butAgdaworksperfectlybecauseofitssyntaxandheavyunificationusage.Thereisalsoanumberof[italicizedcommentsinbrackets]layingaround,usuallyforthosewithtypetheorybackground.Dontbescared,youcancompletelyignorethem.Theygivedeeperinsightsifyouresearchonthem,though.Thelasttwosectionscontaincompletelytypetheoreticstuff.TheyarethereasonIstartedwritingthis,but,still,youmayignorethemcompletelyifyouwish.Youareexpectedtounderstandeverythingelse.Doexercisesandswitchtoothertutorialswhenstuck.
Finally,beforewestart,adisclaimer:Iverifiedmycorethoughtsabouthowallthisstuffworksbyreading(partsof)Agdassourcecode,butstill,asPlatosSocratesstated,IknowthatIknownothing.
SlowstartYouwanttouseEmacs,trustmeThereisagda2modeforEmacs.Itallowsto:
inputfunnyUNICODEsymbolslikeor,interactivelyinteractwithAgda(moreonthatbelow).
Installation:
install emacs ,installeverythingwith agda substringfromyourpackagemanageror Agda and Agdaexecutablewith cabal ,run agdamodesetup .
Running:
run emacs ,press CxCfFileNameRET (Control+x,Control+f,typeFileName,pressReturn/Enterkey).
-
Notethatyoucanloadthisarticle inLiterateAgdaformat(../BrutalDepTypes.lagda)directly intoEmacs.Thisisactuallyarecommendedwaytousethistext,youcantdoexercisesinHTMLversion.
SyntaxInAgdaamoduledefinitionalwaysgoesfirst:
moduleBrutalDepTypeswhere
Nestedmodulesandmoduleswithparametersaresupported.Oneofthemostcommonusagesofnestedmodulesistohidesomedefinitionsfromthetoplevelnamespace:
moduleThrowAwayIntroductionwhere
DatatypesarewritteninGADTsstyle:
dataBool:Setwheretruefalse:BoolNote,wecanlistconstructorsofasametypebyinterspersingthemwithspaces.
inputforis\bn,inputforis\to,but>isfinetooNaturals.data:Setwherezero:succ:
IdentitycontainerdataId(A:Set):Setwherepack:AIdA
inputforis\botEmptytype.Absurd.Falseproposition.data:Setwhere
Set heremeansthesamethingaskind * inHaskell,i.e.atypeoftypes(moreonthatbelow).
Agdaisatotallanguage.Thereisno undefined ,allfunctionsareguaranteedtoterminateonallpossibleinputs(ifnotexplicitlystatedotherwisebyacompilerflagorafunctiondefinitionitself),whichmeansthat typeisreallyempty.
FunctiondeclarationsareverymuchlikeinHaskell:
inputforis\_0,is\_1andsoonid:idx=x
exceptfunctionargumentshavetheirnamesevenintypeexpressions:
-
Note,argument'snameinatypemightdifferfromanameusedinpatternmatchingid:(n:)idx=xthis`x`referstothesameargumentas`n`inthetype
with id sdefinitionbeingasyntaxsugarfor:
id:(_:)idx=x
wheretheunderscoremeansIdontcareaboutthename,justlikeinHaskell.
Dependenttypesallowtypeexpressionsafteranarrowtodependonexpressionsbeforethearrow,thisisusedtotypepolymorphicfunctions:
id:(A:Set)AAid_a=a
Notethatthistime A inthetypecannotbechangedintoanunderscore,butitsfinetoignorethisnameinpatternmatching.
Patternmatchinglooksasusual:
not:BoolBoolnottrue=falsenotfalse=true
exceptifyoumakeanerrorinaconstructorname:
not:BoolBoolnottrue=falsenotfals=true
Agdawillsaynothing.Thismightbecriticalsometimes:
dataThree:SetwhereCOneCTwoCThree:Three
three2:Threethree2COne=zerothree2Ctwo=succzerothree2_=succ(succzero)intersectswiththepreviousclause
Finally,Agdasupportsimplicitarguments:
id:{A:Set}AAida=a
idTest:idTest=id
Valuesofimplicitargumentsarederivedfromotherargumentsvaluesandtypesbysolvingtypeequations
-
(moreonthembelow).Youdonthavetoapplythemorpatternmatchonthemexplicitly,butyoustillcanifyouwish:
positional:id:{A:Set}AAid{A}a=a
idTest:idTest=id{}
named:const:{A:Set}{B:Set}ABAconst{B=_}a_=a
constTest:constTest=const{A=}{B=}
[Its important tonotethatnoproofsearch iseverdone.Implicitargumentsarecompletelyorthogonal tocomputational aspect of a program, being implicit doesnt imply anythingelse. Implicit variables are nottreatedanywayspecial,theyarenottypeerasedanywaydifferentlythanothers.Theyarejustakindofsyntaxsugarassistedbyequationsolving.]
Itsallowedtoskiparrowsbetweenargumentsinparenthesesorbraces:
id:{A:Set}(a:A)Aida=a
andtointerspersenamesofvaluesofthesametypebyspacesinsideparenthesesandbraces:
const:{AB:Set}ABAconsta_=a
WhatmakesAgdassyntaxsoconfusingistheusageofunderscore.InHaskellIdontcareaboutthenameistheonlymeaningforit,inAgdathereareanothertwoandahalf.Thefirstonebeingguessthevalueyourself:
idTest:idTest=id_
whichworksexactlythesamewayasimplicitarguments.
Or, to be more precise, it is the implicit arguments that work like arguments implicitly applied withunderscores,exceptAgdadoesthisonceforeachfunctiondefinition,notforeachcall.
Theanotherhalfbeingguessthetypeyourself:
unpack:{A:_}IdAAunpack(packa)=a
whichhasaspecial syntaxsugar:
-
inputforis\allor\forallunpack:{A}IdAAunpack(packa)=a
explicitargumentversion:unpack:AIdAAunpack_(packa)=a
extendstotherightuptothefirstarrow:
unpack:{AB}IdAIdBAunpack(packa)_=a
unpack:{A}(_:IdA){B}IdBAunpack(packa)_=a
Datatypesyntaxassumesimplicit whenthereisnotypespecified:
dataForAllIdA(B:IdA):Setwhere
ItisimportanttonotethatAgdas isquitedifferentfromHaskells ( forall ).Whenwesay n inAgda its perfectly normal for n: to be inferred, but inHaskell n alwaysmeans {n : Set} ,[i.e.Haskells isanimplicit(HindleyMilner)versionofsecondorderuniversalquantifierwhileinAgdaitsjustasyntaxsugar].
Syntaxmisinterpretingbecomesahugeproblemwhenworkingwithmorethanoneuniverselevel(moreonthat below). It is important to train yourself to desugar type expressions subconsciously (by doing inconsciously at first). It will save hours of your time later. For instance, {A} Id A A means{A:_}(_:IdA)A (wherethelast A shouldbeinterpretedas (_:A) ),i.e.thefirst A isavariablename,whiletheotherexpressionsaretypes.
Finally,thelastmeaningofanunderscoreistomarkargumentsplacesinfunctionnamesforthe MixFixparser,i.e.anunderscoreinafunctionnamemarkstheplacewheretheargumentsgoes:
-
if_then_else_:{A:Set}BoolAAAiftruethenaelse_=aiffalsethen_elseb=b
Aretwosequal?_=?_:Boolzero=?zero=truezero=?succm=falsesuccm=?zero=falsesuccn=?succm=n=?m
Sumfor.infix6_+__+_:zero+n=nsuccn+m=succ(n+m)
ifthenelseTest:ifthenelseTest=if(zero+succzero)=?zerothenzeroelsesucc(succzero)
ListsdataList(A:Set):Setwhere[]:ListA__:AListAListA
[_]:{A:Set}AListA[a]=a[]
listTest:ListlistTest=[]
listTest:ListlistTest=zero(zero(succzero[]))
Notethefixitydeclaration infix whichhasthesamemeaningasinHaskell.Wedidntwrite infixl forareason.WithdeclaredassociativityAgdawouldnotprintredundantparentheses,whichisgoodingeneral,butwouldsomewhatcomplicateexplanationofaseveralthingsbelow.
Thereisa where construct,justlikeinHaskell:
-
ifthenelseTest:ifthenelseTest=if(zero+succzero)=?zerothenzeroelsexwherex=succ(succzero)
Whilepatternmatching,thereisaspecialcasewhenatypewearetryingtopatternmatchonisobviously([typeinhabitanceproblemisundecidableinageneralcase])empty.Thisspecialcaseiscalledanabsurdpattern:
impliesanything.elim:{A:Set}Aelim()
whichallowsyoutoskiparighthandsideofadefinition.
Youcanbindvariableslikethatstill:
Absurdimpliesanything,taketwo.elim:{A:Set}Aelimx=elimx
Agdahasrecords,whichworkverymuch like newtype declarations inHaskell, i.e. theyaredatatypeswithasingleconstructorthatisnotstored.
recordPair(AB:Set):Setwherefieldfirst:Asecond:B
getFirst:{AB}PairABAgetFirst=Pair.first
Note, however, that toprevent nameclashes recorddefinitiongeneratesamodulewith fieldextractorsinside.
Thereisaconventiontodefineatypewithoneelementasarecordwithnofields:
inputforis\topOneelementtype.Recordwithoutfields.Trueproposition.record:Setwhere
tt:tt=record{}
Aspecialthingaboutthisconventionisthatanargumentofanemptyrecordtypeautomaticallygetsthevalue record{} whenappliedimplicitlyorwithunderscore.
Lastly,Agdausesoversimplifiedlexerthatsplitstokensbyspaces,parentheses,andbraces.Forinstance
-
(notethenameofthevariablebinding):
inputforis\`inputforis\'elim:{A:Set}Aelimx:=elimx:
istotallyfine.Alsonotethat doesntgenerateacommenthere.
ThemagicofdependenttypesLetsdefinethedivisionbytwo:
div2:div2zero=zerodiv2(succ(succn))=succ(div2n)
theproblemwiththisdefinitionisthatAgdaistotalandwehavetoextendthisfunctionforoddnumbers
div2(succzero)={!checkme!}
bychanging {!checkme!} intosometerm,mostcommonchoicebeing zero .
Supposenow,weknowthatinputsto div2 arealwaysevenandwedontwanttoextend div2 forthesucczero case.Howdoweconstrain div2 toevennaturalsonly?Withapredicate!Thatis, evenpredicate:
even:Setevenzero=even(succzero)=even(succ(succn))=evenn
whichreturns withwithatrivialproof tt whenargumentisevenandempty thentheargumentisodd.
Nowthedefinitionof div2e constrainedtoevennaturalsonlybecomes:
div2e:(n:)evennNote,wehavetogiveaname`n`tothefirstargumentherediv2ezerop=zerodiv2e(succzero)()div2e(succ(succy))p=succ(div2eyp)Note,aproofof`even(succ(succn))`translatestoaproofof`evenn`bythedefinitionof`even`.
Whenprogrammingwithdependent types,apredicateon A becomesa function from A to types, i.e.ASet . If a:A satisfiesthepredicate P:ASet thenthefunction P returnsatypewitheachelementbeingaproofof Pa ,inacase a doesntsatisfy P itreturnsanemptytype.
Themagicofdependenttypesmakesthetypeofthesecondargumentof div2e changeeverytimewe
-
patternmatchonthefirstargument n .Fromthecalleeside,ifthefirstargumentisoddthenthesecondargumentwouldget typesometime(afteranumberofrecursivecalls)enablingtheuseofanabsurdpattern.Fromthecallerside,wearenotabletocallthefunctionwithanodd n ,sincewehavenomeanstoconstructavalueforthesecondargumentinthiscase.
TypefamiliesandUnificationThereisanotherwaytodefineevenpredicate.Thistimewithadatatypeindexedby:
dataEven:Setwhereezero:Evenzeroe2succ:{n:}EvennEven(succ(succn))
twoIsEven:Even(succ(succzero))twoIsEven=e2succezero
Even:Set isafamilyoftypesindexedbyandobeyingthefollowingrules:
Evenzero hasoneelement ezero .Foranygiven n type Even(succ(succn)) hasoneelementif Evenn isnonempty.Therearenootherelements.
Comparethisto even:Set definitiontranslation:
Thereisatrivialproofthat zero hasproperty even .Thereisnoproofthat succzero hasproperty even .If n hasproperty even thensohas succ(succn) .
In otherwords, thedifference is that Even : Set constructs a typewhereas even : Setreturnsatypewhenappliedtoanelementof .
Theproofthattwoiseven even(succ(succzero)) literallysaystwoisevenbecauseithasatrivialproof,whereastheproofthattwoiseven twoIsEven saystwoisevenbecausezeroisevenandtwoisthesuccessorofthesuccessorofzero.
Even datatypeallowsustodefineanothernonextendeddivisionbytwofor :
div2E:(n:)Evenndiv2Ezeroezero=zerodiv2E(succzero)()div2E(succ(succn))(e2succstilleven)=succ(div2Enstilleven)Comparethiscasetodiv2e.
Note,thereisnocasefor div2Ezero(e2succx) since e2succx hasthewrongtype,thereisnosuchconstructor in Evenzero .For the succzero case the typeof thesecondargument isnot ,but isempty.Howdoweknowthat?Unification!
Unificationisthemostimportant(atleastwithpatternmatchingoninductivedatatypesinvolved)andeasilyforgottenaspectofdependentlytypedprogramming.Giventwoterms M and N unificationtriestofindasubstitution s suchthatusing s on M givesthesameresultasusing s on N .Theprecisealgorithmdefinitionisprettylong,buttheideaissimple:todecideiftwoexpressionscouldbeunifiedwe
-
reducethemasmuchaspossible,thentraversetheirspinesuntilwe
hitanobviousdifferencebetweenthem,findaplacewherewecannotdecideforsure,orsuccessfullyfinishthetraversalgeneratingasubstitution s .
Forinstance:
Tounify[ (succa)+b with succ(c+d) ]weneedreducebothofthem,nowweneedtounify[ succ(a+b) with succ(c+d) ],whichmeansthatweneedtounify[ a+b with c+d ],whichmeansthatweneedtounify[ a with c ]and[ b with d ],whichmeansthat[ a=c , b=d ].Ontheotherhand, succa cannotbeunifiedwith zero forany a ,and succb cannotbeunifiedwith b forany b .Wedontknowifitspossibletounify foon with zero forsomeunknownfunction foo (itmightormightnotreduceto zero forsome n ).
In the code above succ zero doesnt unify with any of the Even constructors indexes [ zero ,succ(succn) ]whichmakesthistypeobviouslyemptybyitsdefinition.
[RefertoTheviewfromtheleftpaperbyMcBrideandMcKinna[20]formoredetailsonpatternmatchingwithtypefamilies.]
MoretypefamiliesandlessUnificationIndatatypedeclarationsthingsbeforea : arecalledparameters,thingsafterthecolonbutbeforea Setarecalledindexes.
Thereisafamousdatatypeinvolvingbothofthem:
dataVec(A:Set):Setwhere[]:VecAzero__:{n}AVecAnVecA(succn)
VecAn isavectorofvaluesoftype A andlength n , Vec hasaparameteroftype Set andisindexedbyvaluesoftype .Comparethisdefinitionto thedefinitionof List and Even .Notealso, thatAgdatoleratesdifferentdatatypeswithconstructorsofthesamename(seebelowforhowthisisresolved).
Wecannotomittheclauseforan [] caseinafunctionwhichtakesaheadofa List :
head:{A}ListAAhead[]={!checkme!}head(aas)=a
butwehavenothingtowriteinplaceof {!checkme!} there(ifwewanttobetotal).
Ontheotherhand,thereisno [] constructorina VecA(succn) type:
head:{An}VecA(succn)Ahead(aas)=a
-
Notethattherearenoabsurdpatternshere, VecA(succn) isinhabited,itjusthappensthatthereisno[] inthere.
Bytheway,the Vec typeisfamousforaconcatenationfunction:
Concatenationfor`List`s_++_:{A}ListAListAListA[]++bs=bs(aas)++bs=a(as++bs)
Concatenationfor`Vec`torsThelengthofaconcatenationisthesumoflengthsofargumentsandisavailableintypes._++v_:{Anm}VecAnVecAmVecA(n+m)[]++vbs=bs(aas)++vbs=a(as++vbs)
Compare _+_ , _++_ ,and _++v_ definitions.
Whydoesthedefinitionof _++v_ work?Becausewedefined _+_ thisway!Inthefirstclauseof _++v_the typeof [] gives n=zero byunification, zero+m=m by the _+_ definition, bs:VecAm .Similarly,inthesecondclause n=succn0 , as:VecAn0 , (succn0)+m=succ(n0+m) bythe_+_ definition, a(as++bs):succ(n0+m) .
DottedpatternsandUnificationLetsdefineasubstraction:
infix6____:zero_=zerosuccnzero=succnsuccnsuccm=nm
Notethat nm=zero for m>n .
Letusgetridofthis (succn)zero casewith __ relation:
data__:Setwherezn:{n}zeronss:{nm}nmsuccnsuccm
Wearenowabletowriteasubstractionthatisnotextendedfor m>n .
sub:(nm:)mnsubnzero(zn.{n})=nsub.(succn).(succm)(ss{m}{n}y)=subnmy
Notethedots,thesearecalleddottedpatterns.Ignorethemforasecond.
-
Consider thecase subnzero(zn{k}) .The typeof the thirdargument is zeron .The typeofzn{k} is zerok .Unificationofthesetwotypesgives[ k=n , m=zero ].Afterasubstitutionweget subnzero(zn{n}) .Whichofthe n swewanttobind/matchon?Inthecodeabovewesayonthefirstandplaceadotbeforethesecondoccurrencetomarkthisintention.Dottedpatternsaysdonotmatchonthis,itistheonlypossiblevaluetothecompiler.
Thesecondclauseis subnm(ss{n'}{m'}y) .Thetypeofthethirdargumentis mn .Thetypeofss{n'}{m'}y is succn'succm' .Thisgives[ n=succn' , m=succm' ].Thistimewedecidedtomatchon n' and m' .
Rewrittenwitha case constructfromHaskell(Agdadoesnthave case ,seebelow)thecodeabovebecomes(inpseudoHaskell):
subnmeven=caseevenofzn{k}>casemof[`k=n`,`m=zero`]zero>nsuccm'>__IMPOSSIBLE__since`m=zero`doesn'tmergewith`m=succm'`ssn'm'y>subn'm'y[`n=succn'`,`m=succn'`]
Where __IMPOSSIBLE__ isjustlikean undefined butisneverexecuted.
Note,thatwehave[ k=n , m=zero ]inthefirstcaseforeven.Thismeanswecandotthefirstusageofzero tooptimizethematchon m away:
sub:(nm:)mnsubn.zero(zn.{n})=nsub.(succn).(succm)(ss{m}{n}y)=subnmy
whichtranslatesto
subnmeven=caseevenofzn{k}>nssn'm'y>subn'm'y
Finally,wecanalsorewrite sub tomatchonthefirsttwoarguments(usual,commonsensedefinition):
sub:(nm:)mnsubnzero(zn.{n})=nsub(succn)(succm)(ss.{m}.{n}y)=subnmy
whichtranslatesintothefollowing:
-
subnmeven=casemofzero>caseevenofzn{k}>nss{k}{l}y>__IMPOSSIBLE__since`zero`(`m`)can'tbeunifiedwith`succk`succm'>casenofzero>caseevenofzn{k}>__IMPOSSIBLE__since`succm'`(`m`)can'tbeunifiedwith`zero`ss{k}{l}y>__IMPOSSIBLE__since`zero`(`n`)can'tbeunifiedwith`succl`succn'>caseevenofzn{k}>__IMPOSSIBLE__since`succn'`(`n`)can'tbeunifiedwith`zero`ss{k}{l}y>subn'm'y
Exercise.WriteouttheunificationconstraintsforthepseudoHaskelltranslationabove.
Note,that subnmp computesthedifferencebetween n and m while sub and sub extractitfromtheproof p .Notealso,thatfor subnzero thethirdargumentisalways zn{n} ,sowewouldliketowrite
sub:(nm:)mnsubnzero.(zn{n})=nsub(succn)(succm)(ss.{m}.{n}y)=subnmy
butAgdadoesntallowthis.Seebelowforwhy.
Wecanwrite
sub:(nm:)mnsubnzero_=nsub(succn)(succm)(ss.{m}.{n}y)=subnmy
still.
Exercise.TranslatethefollowingdefinitionintopseudoHaskellwithunificationconstraints:
sub:(nm:)mnsubnzero(zn.{n})=nsub(succ.n)(succ.m)(ss{m}{n}y)=subnmy
The moral is that dotted patterns are inlined unification constraints. This is why we couldnt dotzn{n} inthefirstclauseof sub ,Agdadidntgeneratesuchaconstraint (itcould,have it triedabitharder).
PropositionalequalityandUnificationWeshallnowdefinethemostusefultypefamily,thatis,MartinLfsequivalence(valuesonlyversion,though):
-
is\==infix4__data__{A:Set}(x:A):ASetwhererefl:xx
For xy:A thetype xy hasexactlyoneconstructor refl if x and y areconvertible, i.e. thereexistsuch z that zx and z y , where is reduces in zero ormore steps. By aconsequence from a ChurchRosser theorem and strong normalization convertibility can be solved bynormalization.Whichmeans thatunificationwillbothcheckconvertibilityand fill inanymissingparts. Inotherwords, xy:A thetype xy hasexactlyoneconstructor refl if x and y unifywitheachother.
Letsprovesomeof __ sproperties:
__issymmetricsym:{A:Set}{ab:A}abbasymrefl=refl
transitivetrans:{A:Set}{abc:A}abbcactransreflrefl=refl
andcongruentcong:{AB:Set}{ab:A}(f:AB)abfafbcongfrefl=refl
Considerthecase sym{A}{a}{b}(refl{x=a}) .Matchingon refl gives[ b=a ]equation,i.e.theclauseactuallyis sym{A}{a}.{a}(refl{x=a}) whichallowstowrite refl ontherighthandside.Otherproofsaresimilar.
Note,wecanprove sym theotherway:
sym:{A:Set}{ab:A}abbasym{A}.{b}{b}refl=refl
sym packs a into refl . sym packs b . Are these two definitions equal? is an interestingphilosophicalquestion.(FromtheAgdaspointofviewtheyare.)
Sincedottedpatternsare justunificationconstraints,youdonthavetodot implicitargumentswhenyoudontbindormatchonthem.
__ type family is called propositional equality. In Agdas standard library it has a bit more generaldefinition,seebelow.
ProvingthingsinteractivelyWith __ wecanfinallyprovesomethingfrombasicnumbertheory.Letsdothisinteractively.
Ourfirstvictimistheassociativityof _+_ .
-
+assoc:abc(a+b)+ca+(b+c)+assocabc={!!}
Noteamark {!!} .Anythingoftheform {!expr!} with expr beinganystring(includingempty)agoalafterabuffer is loadedbyagda2mode.Typing {!!} isquite tedious,so there isashortcut ? .All ?symbolsareautomaticallytransformedinto {!!} whenabufferisloaded.
Goalsappearasgreenholes inabuffer,pressingspecialkeysequenceswhile inagoalallows toaskAgdaquestionsaboutandperformactionsonacode.Inthisdocumentcheckmeinagoalmeansthatthisgoalisnotexpectedtobefilled,itsjustanexample.
Press CcCl (load)toloadandtypecheckthebuffer.
Placingthecursorinthegoalabove(thegreenholeinthetext)andpressing CcCcaRET (caseby a )gives(ignorechangestothenameofafunctionandcheckmeseverywhere):
+assoc:abc(a+b)+ca+(b+c)+assoczerobc={!checkme!}+assoc(succa)bc={!checkme!}
Press CcC, (goaltypeandcontext)whileinthegoal.Thiswillshowthegoaltypeandthecontextinsidethehole.Write refl inthereandpress CcCr (refine),thisgives:
+assoc:abc(a+b)+ca+(b+c)+assoczerobc=refl+assoc(succa)bc={!checkme!}
CcCf (nextgoal),write congsucc there, CcCr :
+assoc:abc(a+b)+ca+(b+c)+assoczerobc=refl+assoc(succa)bc=congsucc{!checkme!}
Nextgoal,goaltypeandcontext,press CcCa (autoproofsearch):
+assoc:abc(a+b)+ca+(b+c)+assoczerobc=refl+assoc(succa)bc=congsucc(+assocabc)
Done.
(InAgda2.3.2youhavetoreloadabufferforproofsearchtowork,itsprobablyabug.)
Similarly,weprove
-
lemma+zero:aa+zeroalemma+zerozero=refllemma+zero(succa)=congsucc(lemma+zeroa)
lemma+succ:absucca+ba+succblemma+succzerob=refllemma+succ(succa)b=congsucc(lemma+succab)
Thecommutativityfor _+_ isnothardtofollowtoo:
Afunwaytowritetransitivityinfixr5_~__~_=trans
+comm:aba+bb+a+commzerob=sym(lemma+zerob)+comm(succa)b=congsucc(+commab)~lemma+succba
Nicewaytostepthroughaproofistowrapsomesubexpressionwith {!!} ,e.g.:
+comm(succa)b=congsucc{!(+commab)!}~lemma+succba
andaskforatype,contextandinferredtypeofagoalwith CcCl followedby CcC. ,refine,wrapanothersubexpression,repeat.Idreamofabetterinterfaceforthis.
SolvingtypeequationsThe second case of +comm is pretty fun example to infer implicit arguments by hand. Lets do that.Algorithmisasfollows:
First,expandallimplicitargumentsandexplicitargumentsappliedwith _ inatermintometavariables,thatis,specialmetalevelvariablesnotboundanywhereintheprogram.Lookatthetypesofallsymbolsandconstructasystemofequations.Forinstance,ifyouseeterm1term2:D , term1:AB and term2:C ,addequations A==C and B==D tothesystem.Solvethesystemwithahelpfromunification.Twopossibleresults:
Allthemetavariablesgottheirvaluesfromthesolution.Success.Therearesomethatdidnt.Thissituationisreportedtoauserasunsolvedmetastypecheckingresult.Theseactlikewarningswhileyouarenottryingtocompileortotypecheckinasafemode.Inthelattertwocasesunsolvedmetastransformintoerrors.
Substitutethevaluesofmetavariablesbackintotheterm.
Applyingthefirststepofthealgorithmtoaterm
trans(congsucc(+comm1ab))(lemma+succba)
gives:
trans{ma}{mb}{mc}{md}(cong{me}{mf}{mg}{mh}succ(+commab))(lemma+succba)
-
with m* beingmetavariables.
ab: since _+_: inthetypeof +comm .Thisgivesthefollowingsystem(withduplicatedequationsandmetavariableapplicationsskipped):
trans(congsucc(+commab))(lemma+succba):__{}(succa+b)(b+succa)trans(congsucc(+commab))(lemma+succba):__{}(succ(a+b))(b+succa)afternormalizationma=mb=succ(a+b)md=b+succa+commab:__{}(a+b)(b+a)mg=(a+b)me=mh=(b+a)mf=congsucc(+commab):__{}(succ(a+b))(succ(b+a))mc=succ(b+a)lemma+succba:__{}(succb+a)(b+succa)lemma+succba:__{}(succ(b+a))(b+succa)afternormalizationtrans(congsucc(+commab))(lemma+succba):__{}(succa+b)(b+succa)
ThemostawesomethingaboutthisisthatfromAgdaspointofview,agoalisjustametavariableofaspecialkind.Whenyouaskforatypeofagoalwith CcCt or CcC, Agdaprintseverythingithasforthecorrespondingmetavariable.Funnythingslike ?0 , ?1 ,andetcinagda2modeoutputsarereferencestothesemetavariables.Forinstance,inthefollowing:
metaVarTest:Vec(div2(succzero))metaVarTest={!checkme!}
thetypeofthegoalmentionsthenameofveryfirstgoalmetavariablefromthisarticle.
By the way, to resolve datatype constructor overloading Agda infers the type for a constructor callexpectedat the call site, andunifies the inferred typewith the typesof all possible constructorsof thesamename. If therearenomatches found,anerror is reported. Incasewithmore thanonealternativeavailable,anunsolvedmeta(forthereturntypemetavariable)isproduced.
Terminationchecking,wellfoundedinductionWorkinprogress.
PropositionalequalityexercisesExercise.Definemultiplicationbyinductiononthefirstargument:
moduleExercisewhereinfix7_*__*_:n*m={!!}
-
sothatthefollowingproofworks:
Distributivity.*+dist:abc(a+b)*ca*c+b*c*+distzerobc=reflis\lambda*+dist(succa)bc=cong(xc+x)(*+distabc)~sym(+assocc(a*c)(b*c))
Now,fillinthefollowinggoals:
*assoc:abc(a*b)*ca*(b*c)*assoczerobc=refl*assoc(succa)bc=*+distb(a*b)c~cong{!!}(*assocabc)
lemma*zero:aa*zerozerolemma*zeroa={!!}
lemma+swap:abca+(b+c)b+(a+c)lemma+swapabc=sym(+assocabc)~{!!}~+assocbac
lemma*succ:aba+a*ba*succblemma*succab={!!}
*comm:aba*bb*a*commab={!!}
Pressing CcC. whilethereisaterminaholeshowsagoaltype,contextandthetermsinferredtype.Incrediblyusefulkeysequenceforinteractiveproofediting.
Patternmatchingwith withConsiderthefollowingimplementationofa filter functioninHaskell:
filter::(aBool)[a][a]filterp[]=[]filterp(a:as)=casepaofTrue>a:(filterpas)False>filterpas
ItcouldberewrittenintoAgdalikethis:
filter:{A:Set}(ABool)ListAListAfilterp[]=[]filterp(aas)withpa...|true=a(filterpas)...|false=filterpas
whichdoesntlookverydifferent.Butdesugaring ... bytherulesofAgdasyntaxmakesitabitless
-
similar:
filter:{A:Set}(ABool)ListAListAfilterp[]=[]filterp(aas)withpafilterp(aas)|true=a(filterpas)filterp(aas)|false=filterpas
Theresnodirectanalogueto case inAgda, with constructionallowspatternmatchingonintermediateexpressions(justlikeHaskells case ),but(unlike case )onatoplevelonly.Thus with effectively justaddsaderivedargumenttoafunction.Just likewithnormalarguments,patternmatchingonaderivedargumentmightchangesometypesinacontext.
The top level restrictionsimplifiesall thedependently typedstuff (mainly related todottedpatterns),butmakessomethingsalittlebitmoreawkward(inmostcasesyoucanemulate case withasubtermplacedintoa where block).Syntactically,verticalbarsseparatenormalarguments fromaderivedonesandaderivedonesfromeachother.
Obfuscatingthefunctionabovegives:
filterN:{A:Set}(ABool)ListAListAfilterNp[]=[]filterNp(aas)withpafilterNp(aas)|truewithasfilterNp(aas)|true|[]=a[]filterNp(aas)|true|bbswithpbfilterNp(aas)|true|bbs|true=a(bfilterNpbs)filterNp(aas)|true|bbs|false=afilterNpbsfilterNp(aas)|false=filterNpasoralternativelyfilterP:{A:Set}(ABool)ListAListAfilterPp[]=[]filterPp(a[])withpafilterPp(a[])|true=a[]filterPp(a[])|false=[]filterPp(a(bbs))withpa|pbfilterPp(a(bbs))|true|true=a(bfilterPpbs)filterPp(a(bbs))|true|false=afilterPpbsfilterPp(a(bbs))|false|true=bfilterPpbsfilterPp(a(bbs))|false|false=filterPpbs
whichshowsthat with couldbenestedandmultiplematchesareallowedtobedoneinparallel.
Letusprovethatallthesefunctionsproduceequalresultswhenappliedtoequalarguments:
filterfilterN:{A:Set}(p:ABool)(as:ListA)filterpasfilterNpasfilterfilterNp[]=reflfilterfilterNp(aas)={!checkme!}
-
notethegoaltype (filterp(aas)|pa)(filterNp(aas)|pa) whichshows pa asderivedargumentto filter function.
Rememberthattoreduce a+b wehadtomatchon a intheproofsabove,matchingon b gavenothinginterestingbecause _+_ wasdefinedbyinductiononthefirstargument.Similarly,tofinishthefilterfilterN proofwehavetomatchon pa , as ,and pb ,essentiallyduplicatingtheformoffilterN term:
filterfilterN:{A:Set}(p:ABool)(as:ListA)filterpasfilterNpasfilterfilterNp[]=reflfilterfilterNp(aas)withpafilterfilterNp(aas)|truewithasfilterfilterNp(aas)|true|[]=reflfilterfilterNp(aas)|true|bbswithpbfilterfilterNp(aas)|true|bbs|true=cong(xa(bx))(filterfilterNpbs)filterfilterNp(aas)|true|bbs|false=cong(__a)(filterfilterNpbs)filterfilterNp(aas)|false=filterfilterNpas
Exercise.Guessthetypesfor filterfilterP and filterNfilterP .Arguewhichoftheseiseasiertoprove?Doit(andgettheotheronealmostforfreebytransitivity).
Rewritingwith with andUnificationWhenplayingwiththeproofsaboutfiltersyoumighthadnoticedthat with doessomethinginterestingwithagoal.
Inthefollowinghole
filterfilterN:{A:Set}(p:ABool)(as:ListA)filterpasfilterNpasfilterfilterNp[]=reflfilterfilterNp(aas)={!checkme!}
thetypeofthegoalis (filterp(aas)|pa)(filterNp(aas)|pa) .Butafterthefollowing with
filterfilterN:{A:Set}(p:ABool)(as:ListA)filterpasfilterNpasfilterfilterNp[]=reflfilterfilterNp(aas)withpa|as...|r|rs={!checkme!}
itbecomes (filterp(ars)|r)(filterNp(ars)|r) .
Samethingsmighthappennotonlytoagoalbuttoacontextasawhole:
strangeid:{A:Set}{B:ASet}(a:A)(b:Ba)Bastrangeid{A}{B}abawithBa...|r={!checkme!}
inthehole,boththetypeof ba andthegoalstypeare r .
-
Fromtheseobservationsweconcludethat withexpr createsanewvariable,say w ,andbackwardssubstitutes expr to w inacontext,changingalltheoccurrencesof expr thetypesofthecontextto w .Whichmeansthatinaresultingcontexteverytypethathad expr asasubtermstartsdependendingonw .
Thispropertyallowsusing with forrewriting:
lemma+zero:aa+zeroalemma+zerozero=refllemma+zero(succa)witha+zero|lemma+zeroalemma+zero(succa)|._|refl=refl
sameexpressionwithexpandedunderscore:lemma+zero:aa+zeroalemma+zerozero=refllemma+zero(succa)witha+zero|lemma+zeroalemma+zero(succa)|.a|refl=refl
Intheseterms a+zero isreplacedbyanewvariable,say w ,whichgives lemma+zeroa:aw .Patternmatching on refl gives [ w = a ] and so the dotted pattern appears. After that the goal typebecomes aa .
Thispattern
fpswitha|eqn...|._|refl=rhs
issocommonthatithasitsownshorthand(https://lists.chalmers.se/pipermail/agda/2009/001513.html):
fpsrewriteeqn=rhs
Exercise.Prove (onpaper) that rewritingagoal typewith with andpropositional equality isa syntaxsugarforexpressionsbuiltfrom refl , sym , trans and cong .
UniversesandpostulatesWhenmoving fromHaskell toAgdaexpression every type isofkind * , i.e. forany type X , X:* transformsintoeverygroundtypeisoftype Set ,i.e.foranygroundtype X , X:Set .Ifwearewillingtobeconsistent,wecantafford Set:Set becauseit leadstoanumberofparadoxes(moreonthembelow).Still,wemightwanttoconstructthingslikealistoftypesandourcurrentimplementationof Listcannotexpressthis.
TosolvethisproblemAgdaintroducesaninfinitetowerof Set s,i.e. Set0:Set1 , Set1:Set2 ,andsoon with Set being an alias for Set0 . Agda is also a predicative system which means thatSet0Set0:Set1 , Set0Set1:Set2 ,andsoon,butnot Set0Set1:Set1 .Note,however,thatthistowerisnotcumulative,e.g. Set0:Set2 and Set0Set1:Set3 arefalsetypingjudgments.
[AsfarasIknow,intheorynothingpreventsusfrommakingthetowercumulative,itsjustsohappenedthatAgdaselected this routeandnotanother.Predicativity isamuchmoresubtlematter (moreon thatbelow).]
-
Alistoftypesnowbecomes:
dataList1(A:Set1):Set1where[]:List1A__:AList1AList1A
whichlooksverymuchliketheusual List definition.
TopreventacodeduplicationlikethatAgdaallowsuniversepolymorphicdefinitions.TodefinethetypeLevel ofuniverselevelsweneedabitofpostulatemagic:
postulateLevel:Setpostulatelzero:Levelpostulatelsucc:LevelLevelpostulate__:LevelLevelLevel
Postulatesessentiallydefinepropositionswithoutproofs,i.e.theysaytrustme,Iknowthistobetrue.Obviously,thiscanbeexploitedtoinfercontradictions:
postulateundefined:{A:Set}A
butforeverypostulateAgdaexpectstobesafethereisa BUILTIN pragmathatchecksthepostulateddefinitionpromotingitfromasimplepostulatetoanaxiom.For Level therearethefollowing BUILTIN s:
{#BUILTINLEVELLevel#}{#BUILTINLEVELZEROlzero#}{#BUILTINLEVELSUClsucc#}{#BUILTINLEVELMAX__#}
The Level typeworksverymuchlike .Ithastwoconstructors lzero and lsucc thatsignifyzeroand successor, there is also an operator __ which returns a maximum from its arguments. Thedifferencebetween and Level isthatwearenotallowedtopatternmatchonelementsofthelatter.
Giventhedefinitionabove,expression Set for :Level meansthe Set oflevel .
Wearenowabletodefineuniversepolymorphiclistinthefollowingway:
dataPList{:Level}(A:Set):Setwhere[]:PListA__:APListAPListAorabitnicer:dataPList{}(A:Set):Setwhere[]:PListA__:APListAPListA
ItisinterestingtonotethatAgdacouldhavegoneanotherroute,sayGHCroute,bydefiningallthebuiltinthingsinsidewithfixednames.Instead, BUILTIN pragmaallowsustoredefinethenamesofthebuiltins,which isveryhelpfulwhenwewant towriteourownstandard library.This isexactlywhatwearenowgoingtodo.
-
LibraryModulesandtheendofthrowawaycodeNotethatwehavebeenwritingeverythingaboveinsideamodulecalled ThrowAwayIntroduction .Fromhereonwearegoingto(mostly)forgetaboutitandwriteasmallstandardlibraryforAgdafromscratch.TheideaistoremoveanymodulewithanameprefixedbyThrowAwayfromthisfiletoproducethelibrarycode.Tomaketheimplementationofthisideaassimpleaspossibleweplacemarkerslike:
{endofThrowAwayIntroduction}
attheendsofthrowawaycode.Itallowstogeneratethelibrarybyasimpleshellcommand:
catBrutalDepTypes.lagda|sed'/^\\begin{code}/,/^\\end{code}/!d;/^\\begin{code}/d;/^\\end{code}/c\'|sed'/^*moduleThrowAway/,/^*.endofThrowAway/d;'
Wearenowgoingtoredefineeverythingusefulfromaboveinauniversepolymorphicway(whenapplicable),startingwith Level s:
moduleLevelwhereUniverselevelspostulateLevel:Setpostulatelzero:Levelpostulatelsucc:LevelLevelinputforis\sqcuppostulate__:LevelLevelLevel
infixl5__
Makethemwork{#BUILTINLEVELLevel#}{#BUILTINLEVELZEROlzero#}{#BUILTINLEVELSUClsucc#}{#BUILTINLEVELMAX__#}
EachmoduleinAgdahasanexportlist.Everythingdefinedinamodulegetsappendedtoit.Toplacethingsdefinedforexportinanothermoduleintoacurrentcontextthereisan open construct:
openModuleName
Thisdoesntappend ModuleName sexportlisttocurrentmodulesexportlist.Todothatweneedtoaddpublic keywordattheend:
openLevelpublic
Commonfunctionswithtypesnotforthefaintofheart
-
Exercise.Understandwhatisgoingonintypesofthefollowingfunctions:
moduleFunctionwhereDependentapplicationinfixl0_$__$_:{}{A:Set}{B:ASet}(f:(x:A)Bx)((x:A)Bx)f$x=fx
Simpleapplicationinfixl0_$__$_:{}{A:Set}{B:Set}(AB)(AB)f$x=f$x
inputforis\oDependentcomposition__:{}{A:Set}{B:ASet}{C:{x:A}BxSet}(f:{x:A}(y:Bx)Cy)(g:(x:A)Bx)((x:A)C(gx))fg=xf(gx)
Simplecomposition__:{}{A:Set}{B:Set}{C:Set}(BC)(AB)(AC)fg=fg
Flipflip:{}{A:Set}{B:Set}{C:ABSet}((x:A)(y:B)Cxy)((y:B)(x:A)Cxy)flipfxy=fyx
Identityid:{}{A:Set}AAidx=x
Constantfunctionconst:{}{A:Set}{B:Set}
-
(ABA)constxy=x
openFunctionpublic
Especiallynotethescopesofvariablebindingsintypes.
LogicIntuitionistic Logic module:
moduleLogicwhereinputforis\botFalsepropositiondata:Setwhere
inputforis\topTruepropositionrecord:Setwhere
impliesanythingatanyuniverselevelelim:{}{A:Set}Aelim()
Propositionalnegationisdefinedasfollows:
inputforis\lnot:{}SetSetP=P
The technical part of the idea of this definition is that the principle of explosion (from a contradiction,anythingfollows)getsaprettystraightforwardproof.
Exercise.Provethefollowingpropositions:
-
moduleThrowAwayExercisewherecontradiction:{}{A:Set}{B:Set}AABcontradiction={!!}
contraposition:{}{A:Set}{B:Set}(AB)(BA)contraposition={!!}
contraposition:{}{A:Set}{B:Set}(AB)(BA)contraposition={!!}
:{}{A:Set}A(A)a={!!}
:{}{A:Set}((A))A={!!}
Hint.Use CcC, heretoseethegoaltypeinitsnormalform.
Fromamore logical standpoint the idea of is that false proposition P should be isomorphic to (i.e.theyshouldimplyeachother: PP ).Since P istrueforall P thereisonly Pleftforustoprove.
Fromacomputationalpointofviewhavingavariableoftype inacontextmeansthatthereisnowayexecutionofaprogramcouldreachthispoint.Whichmeanswecanmatchonthevariableanduseabsurdpattern, elim doesexactlythat.
Notethat,beinganintuitionisticsystem,Agdahasnomeanstoprovedoublenegationrule.Seeforyourself:
:{}{A:Set}(A)Aa={!checkme!}{endofThrowAwayExercise}
By the way, proofs in the exercise above amounted to a serious scientific paper at the start of 20thcentury.
Solutionfortheexercise:
-
privatemoduleDummyAB{}{A:Set}{B:Set}wherecontradiction:AABcontradictionaa=elim(aa)
contraposition:(AB)(BA)contraposition=flip__
contraposition:(AB)(BA)contraposition=flip
openDummyABpublic
privatemoduleDummyA{}{A:Set}where:A(A)=contradiction
:((A))Aa=a
openDummyApublic
Exercise.Understandthissolution.
Noteclevermoduleusage.Openingamodulewithparametersprefixestypesofallthethingsdefinedtherewiththeseparameters.Wewillusethistrickalot.
Letusdefineconjunction,disjunction,andlogicalequivalence:
inputforis\andrecord__{}(A:Set)(B:Set):Set()whereconstructor_,_fieldfst:Asnd:B
open__public
inputforis\ordata__{}(A:Set)(B:Set):Set()whereinl:AABinr:BAB
inputforis\__:{}(A:Set)(B:Set)Set()AB=(AB)(BA)
-
Makeallthisgoodnessavailable:
openLogicpublic
MLTT:typesandpropertiesSomedefinitionsfromPerMartinLfstypetheory[12]:
moduleMLTTwhereinputforis\==Propositionalequalityinfix4__data__{}{A:Set}(x:A):ASetwhererefl:xx
inputforis\SigmaDependentpairrecord{}(A:Set)(B:ASet):Set()whereconstructor_,_fieldprojl:Aprojr:Bprojl
openpublic
Makerewritesyntaxwork{#BUILTINEQUALITY__#}{#BUILTINREFLrefl#}
The typeisadependentversionof __ (thesecondfielddependsonthefirst),i.e. __ isaspecificcaseof :
inputforis\x__:{}(A:Set)(B:Set)Set()AB=A(_B)
:{}{A:Set}{B:Set}(AB)(AB)=(zprojlz,projrz),(zfstz,sndz)
Personally,Iuseboth __ and __ occasionallysince __ looksuglyinthenormalformandmakesgoaltypeshardtoread.
Someproperties:
-
modulePropwhereprivatemoduleDummyA{}{A:Set}where__issymmetricsym:{xy:A}xyyxsymrefl=refl
__istransitivetrans:{xyz:A}xyyzxztransreflrefl=refl
__issubstitutivesubst:{}{P:ASet}{xy}xyPxPysubstreflp=p
privatemoduleDummyAB{}{A:Set}{B:Set}where__iscongruentcong:(f:AB){xy}xyfxfycongfrefl=refl
subst:{}{P:ABSet}{xyuv}xyuvPxuPyvsubstreflreflp=p
privatemoduleDummyABC{}{A:Set}{B:Set}{C:Set}wherecong:(f:ABC){xyuv}xyuvfxufyvcongfreflrefl=refl
openDummyApublicopenDummyABpublicopenDummyABCpublic
Makeallthisgoodnessavailable:
openMLTTpublic
DecidablepropositionsmoduleDecidablewhere
Decidablepropositionitisapropositionthathasanexplicitproofordisproval:
dataDec{}(A:Set):Setwhereyes:(a:A)DecAno:(a:A)DecA
-
Thisdatatypeisverymuchlike Bool ,exceptitalsoexplainswhythepropositionholdsorwhyitmustnot.
Decidablepropositionsarethegluethatmakeyourprogramworkwiththerealworld.
Supposewewanttowriteaprogramthatreadsanaturalnumber,say n ,from stdin anddividesitbytwowith div2E .Todothatweneedaproofthat n is Even .Theeasiestwaytodoitistodefineafunctionthatdecidesifagivennaturalis Even :
moduleThrowAwayExamplewhereopenThrowAwayIntroduction
Even+2:{n}(Evenn)(Even(succ(succn)))Even+2en(e2succen)=contradictionenen
Even?:nDec(Evenn)Even?zero=yesezeroEven?(succzero)=no(())noteanabsurdpatterninananonymouslambdaexpressionEven?(succ(succn))withEven?n...|yesa=yes(e2succa)...|noa=no(Even+2a){endofThrowAwayExample}
thenread n from stdin ,feeditto Even? ,matchontheresultandcall div2E if n is Even .
Sameideaappliestoalmosteverything:
Wanttowriteaparser?Parserisaprocedurethatdecidesifastringconformstoasyntax.Wanttotypecheckaprogram?Typecheckerisaprocedurethatdecidesiftheprogramconformstoagivensetoftypingrules.Wantanoptimizingcompiler?Parse,matchon yes ,typecheck,matchon yes ,optimizetypedrepresentation,generateoutput.Andsoon.
Usingsameideawecandefinedecidabledichotomousandtrichotomouspropositions:
dataDi{}(A:Set)(B:Set):Set()wherediyes:(a:A)(b:B)DiABdino:(a:A)(b:B)DiAB
dataTri{}(A:Set)(B:Set)(C:Set):Set(())wheretri:(a:A)(b:B)(c:C)TriABC
Makeallthisgoodnessavailable:
openDecidablepublic
Naturalnumbers:operations,propertiesandrelations
-
Considerthistobetheanswer(encryptedwith rewrite s)fortheexercisewayabove:
moduleDatawhereNaturalnumbers(positiveintegers)data:Setwherezero:succ:
moduleRelwhereinfix4____
data__:Setwherezn:{n}zeronss:{nm}nmsuccnsuccm
_m=m
- >m(n
-
*isassociative*assoc:abc(a*b)*ca*(b*c)*assoczerobc=refl*assoc(succa)bcrewrite*+distb(a*b)c|*assocabc=refl
privatemoduleDummywherelemma*zero:aa*zerozerolemma*zerozero=refllemma*zero(succa)=lemma*zeroa
lemma+swap:abca+(b+c)b+(a+c)lemma+swapabcrewritesym(+assocabc)|+commab|+assocbac=refl
lemma*succ:aba+a*ba*succblemma*succzerob=refllemma*succ(succa)brewritelemma+swapab(a*b)|lemma*succab=refl
openDummy
*iscommutative*comm:aba*bb*a*commzerob=sym$lemma*zerob*comm(succa)brewrite*commab|lemma*succba=refl
moduleRelOpwhereopenRelopenOpopenProp
infix4_?__?__
- _
-
openDummyApublic
moduleDataVecwhereVectorinfixr5__dataVec{}(A:Set):Setwhere[]:VecAzero__:{n}AVecAnVecA(succn)
moduleVecOpwhereopenOp
privatemoduleDummyA{}{A:Set}whereSingleton`Vec`[_]:AVecA(succzero)[a]=a[]
Concatenationfor`Vec`sinfixr5_++__++_:{nm}VecAnVecAmVecA(n+m)[]++bs=bs(aas)++bs=a(as++bs)
head:{n}VecA(succn)Ahead(aas)=a
tail:{n}VecA(succn)Atail(aas)=a
openDummyApublic
{Workinprogress.TODO.
Ifindthefollowingdefinitionquiteamusing:
moduleVecListswhereopenDataVec
privatemoduleDummyA{}{A:Set}whereVecList=(VecA)}
Beingina List
-
Indexingallowstodefineprettyfunthings:
moduleThrowAwayMorewhereopenDataListopenListOp
inputforis\in`a`isin`List`data__{}{A:Set}(a:A):ListASetwherehere:{as}a(aas)there:{bas}aasa(bas)
inputforis\sub=`xs`isasublistof`ys`__:{}{A:Set}ListAListASetasbs={x}xasxbs
The __ relationsaysthatbeingina List foranelement a:A meansthat a intheheadofa Listor inthetailofa List .Forsome a and as avalueoftype aas ,thatis a is ina list as isapositionofanelement a in as (theremightbeanynumberofelementsinthistype).Relation ,thatisbeingasublist,carriesafunctionthatforeach a in xs givesitspositionin as .
Examples:
listTest=zerozerosucczero[]listTest=zerosucczero[]
Test:zerolistTestTest=here
Test:zerolistTestTest=therehere
Test:listTestlistTestTesthere=hereTest(therehere)=there(therehere)Test(there(there()))
Letusprovesomepropertiesfor relation:
-
++left:{A:Set}(asbs:ListA)as(bs++as)++leftas[]n=n++leftas(bbs)n=there(++leftasbsn)
++right:{A:Set}(asbs:ListA)as(as++bs)++right[]bs()++right(aas)bshere=here++right(aas)bs(theren)=there(++rightasbsn){endofThrowAwayMore}
Notehowtheseproofsrenumberelementsofagivenlist.
Beingina List generalized:AnyBygeneralizing __ relationfrompropositionalequality(in x(xxs) both x sarepropositionallyequal)toarbitrarypredicateswearriveat:
moduleDataAnywhereopenDataListopenListOp
Someelementofa`List`satisfies`P`dataAny{}{A:Set}(P:ASet):ListASet()wherehere:{aas}(pa:Pa)AnyP(aas)there:{aas}(pas:AnyPas)AnyP(aas)
moduleMembership{}{A:Set}{B:Set}(P:BASet)whereinputforis\in`Pba`holdsforsomeelement`a`fromthe`List`whenPis`__`thisbecomestheusual"isin"relation__:BListASet()bas=Any(Pb)as
inputforis\notin__:BListASet()bas=(bas)
inputforis\sub=__:ListAListASet()asbs={x}xasxbs
inputforis\sub=n__:ListAListASet()asbs=(asbs)
inputforis\sup=__:ListAListASet()
-
asbs=(asbs)(bsas)
refl:{as}asasrefl=id
trans:{asbscs}asbsbscsascstransfg=gf
refl:{as}asasrefl=id,id
sym:{asbs}asbsbsassym(f,g)=g,f
trans:{asbscs}asbsbscsascstransfg=(fstgfstf),(sndfsndg)
[]:{b}b[][]()
WhenPis`__`thisbecomes`b[a]ba`singletonP:{ab}b[a]PbasingletonP(herepba)=pbasingletonP(there())
Psingleton:{ab}Pbab[a]Psingletonpba=herepba
++left:(asbs:ListA)as(bs++as)++leftas[]n=n++leftas(bbs)n=there(++leftasbsn)
++right:(as:ListA)(bs:ListA)as(as++bs)++right[]bs()++right(xas)bs(herepa)=herepa++right(xas)bs(theren)=there(++rightasbsn)
filter:{}{Q:ASet}(q:xDec(Qx))(as:ListA)filterqasasfilterq[]()filterq(aas)nwithqafilterq(aas)(herepa)|yesqa=herepafilterq(aas)(theren)|yesqa=there(filterqasn)filterq(aas)n|noqa=there(filterqasn)
Exercise.Notehowgeneralthiscodeis. filter coversabroadsetofpropositions,withfilteredlistisasublist(intheusualsense)oftheoriginallistbeingaspecialcase.Do CcC. inthefollowinggoaland
-
explainthetype:
moduleThrowAwayMorewheregoal={!DataAny.Membership.filter!}{endofThrowAwayMore}
Explainthetypesofallthetermsin Membership module.
Dualpredicate:All{Workinprogress.TODO.
Ididn'thaveachancetouse`All`yet(andI'mtoolazytoimplementthismodulerightnow),buthereisthedefinition:
moduleDataAllwhereopenDataListAllelementsofa`List`satisfy`P`dataAll{}{A:Set}(P:ASet):ListASet()where[]:AllP[]__:{aas}PaAllPasAllP(aas)}
BooleansArenotthatneededwith Dec ,actually.
-
moduleDataBoolwhereBooleansdataBool:Setwheretruefalse:Bool
moduleBoolOpwhereif_then_else_:{}{A:Set}BoolAAAiftruethenaelse_=aiffalsethen_elseb=b
not:BoolBoolnottrue=falsenotfalse=true
and:BoolBoolBoolandtruex=xandfalse_=false
or:BoolBoolBoolorfalsex=xortruex=true
openDataBoolpublic
OtherstuffWorkinprogress.TODO.WeneedtoprovesomethingfromAtoZ.Quicksortmaybe.
PretheoreticalcornerThissectiondiscussesinterestingthingsaboutAgdawhicharesomewhereinbetweenpracticeandpuretheory.
moduleThrowAwayPreTheorywhereopenPropopenOp
EqualityandunificationRewritingwithequalityhidesacoupleofcatches.
Rememberthetermof lemma+zero fromabove:
-
lemma+zero:aa+zeroalemma+zerozero=refllemma+zero(succa)witha+zero|lemma+zeroalemma+zero(succa)|._|refl=refl
ittypechecks,butthefollowingproofdoesnt:
lemma+zero:aa+zeroalemma+zerozero=refllemma+zero(succa)witha|lemma+zeroalemma+zero(succa)|._|refl=refl
Theproblemhereisthatforarbitraryterms A and B topatternmatchon refl:AB these A and Bmustunify.In lemma+zero casewehave a+zero backwardsubstitutedintoanewvariable w ,thenwematchon refl weget wa .Ontheotherhand,in lemma+zero casewehave a changedintow ,an refl gets w+zerow typewhichisamalformed(recursive)unificationconstraint.
Thereisanothercatch.Ourcurrentdefinitionof __ allowstoexpressequalityontypes,e.g. Bool .
Thisenablesustowritethefollowingterm:
lemmaunsafeeq:(P:Bool)BoollemmaunsafeeqPbwithBool|PlemmaunsafeeqPb|.|refl=b+succzero
whichtypecheckswithouterrors.
Note,however,that lemmaunsafeeq cannotbeprovenbysimplypatternmatchingon P :
lemmaunsafeeq:(P:Bool)Boollemmaunsafeeqreflb=b
{endofThrowAwayPreTheory}
Exercise. lemmaunsafeeq isafoodforthoughtaboutcomputationsafetyunderfalseassumptions.
TheoreticalcornerInthissectionweshalltalkaboutsometheoreticalstufflikedatatypeencodingsandparadoxes.Youmightwanttoreadsomeofthetheoreticalreferenceslike[10],[12]first.
moduleThrowAwayTheorywhere
InliteratureAgdasarrow (x:X)Y (where Y mighthave x free)iscalleddependentproducttype,ortype(Pitype)forshort.Dependentpair iscalleddependentsumtype,ortype(Sigmatype)forshort.
Finitetypes
-
Given , and Bool itispossibletodefineanyfinitetype,thatisatypewithfinitenumberofelements.
moduleFiniteTypeswhereopenBoolOp
__:(AB:Set)SetAB=Bool(xifxthenAelseB)
zero=one=two=Boolthree=onetwofour=twotwoandsoon
TODO.Saysomethingaboutextensionalsettingand = .
SimpledatatypesmoduleDatatypeswhere
Given finite types,types,andtypes it ispossible todefinenoninductivedatatypesusing thesameschemethedefinitionof __ uses.
Noninductivedatatypewithoutindexeshasthefollowingscheme:
dataDataTypeName(Param1:Param1Type)(Param2:Param2Type)...:SetwhateverCons1:(Cons1Arg1:Cons1Arg1Type)(Cons1Arg2:Cons1Arg2Type)...DataTypeNameParam1Param2...Cons2:(Cons2Arg1:Cons2Arg1Type)...DataTypeNameParam1Param2......ConsN:(ConsNArg1:ConsNArg1Type)...DataTypeNameParam1Param2...
Reencodedintotypes,types,andfinitetypesitbecomes:
DataTypeName:(Param1:Param1Type)(Param2:Param2Type)...SetwhateverDataTypeNameParam1Param2...=FiniteTypeWithNElementschoicewherechoice:FiniteTypeWithNElementsSetwhateverchoiceelement1=Cons1Arg1Type(Cons1Arg1Cons1Arg2Type(Cons1Arg2...))choiceelement2=Cons2Arg1Type(Cons2Arg1...)...choiceelementN=ConsNArg1Type(ConsNArg1...)
Forinstance, Di typefromabovetranslatesinto:
-
Di:{}(A:Set)(B:Set)Set()Di{}{}AB=Boolchoicewherechoice:BoolSet()choicetrue=ABchoicefalse=AB
DatatypeswithindicesWorkinprogress.TODO.Thegeneralidea:addthemasparametersandplaceanequalityproofinside.
RecursivedatatypesWorkinprogress.TODO.Generalideas:Wtypesand.
CurrysparadoxNegativeoccurrencesmakethesysteminconsistent.
Copythistoaseparatefileandtypecheck:
{#OPTIONSnopositivitycheck#}moduleCurrysParadoxwheredataCS(C:Set):Setwherecs:(CSCC)CSC
paradox:{C}CSCCparadox(csb)=b(csb)
loop:{C}Cloop=paradox(csparadox)
contr:contr=loop
UniversesandimpredicativityWorkinprogress.TODO.*Russellsparadox*Hurkensparadox
{endofThrowAwayTheory}
References[1] Wiki, Agda Tutorials list. [Online]. Available: http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Othertutorials(http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Othertutorials)
[2] Wiki, Agda: Documentation. [Online]. Available: http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Documentation(http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Documentation)
-
[3] A. Setzer, Interactive Theorem Proving for Agda Users. [Online]. Available:http://www.cs.swan.ac.uk/~csetzer/lectures/intertheo/07/interactiveTheoremProvingForAgdaUsers.html(http://www.cs.swan.ac.uk/~csetzer/lectures/intertheo/07/interactiveTheoremProvingForAgdaUsers.html)
[4] A. Bove and P. Dybjer, Dependent Types at Work. [Online]. Available:http://www.cse.chalmers.se/~peterd/papers/DependentTypesAtWork.pdf(http://www.cse.chalmers.se/~peterd/papers/DependentTypesAtWork.pdf)
[5] U. Norell, Dependently Typed Programming in Agda. [Online]. Available:http://www.cse.chalmers.se/~ulfn/papers/afp08/tutorial.pdf(http://www.cse.chalmers.se/~ulfn/papers/afp08/tutorial.pdf)
[6] T. Altenkirch, Computer Aided Formal Reasoning. [Online]. Available:http://www.cs.nott.ac.uk/~txa/g53cfr/(http://www.cs.nott.ac.uk/~txa/g53cfr/)
[7]Coq: Documentation. [Online]. Available: http://coq.inria.fr/documentation(http://coq.inria.fr/documentation)
[8]Idris: Documentation. [Online]. Available: http://idrislang.org/documentation (http://idrislang.org/documentation)
[9]Epigram.[Online].Available:http://www.epig.org/(http://www.epig.org/)
[10] M.H.B. Srensen and P. Urzyczyn, Lectures on the CurryHoward Isomorphism. 1998 [Online].Available: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.17.7385(http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.17.7385)
[11] S. Thompson, Type Theory and Functional Programming. [Online]. Available:https://www.cs.kent.ac.uk/people/staff/sjt/TTFP/(https://www.cs.kent.ac.uk/people/staff/sjt/TTFP/)
[12] P. MartinLf, Intuitionistic type theory. Notes by Giovanni Sambin. [Online]. Available:http://www.csie.ntu.edu.tw/~b94087/ITT.pdf(http://www.csie.ntu.edu.tw/~b94087/ITT.pdf)
[13] P. MartinLf, Intuitionistic type theory. [Online]. Available:http://intuitionistic.files.wordpress.com/2010/07/martinloftt.pdf(http://intuitionistic.files.wordpress.com/2010/07/martinloftt.pdf)
[14] B. Nordstrm, K. Petersson, and J.M. Smith, Programming in MartinLfs Type Theory. AnIntroduction. [Online]. Available: http://www.cse.chalmers.se/research/group/logic/book/(http://www.cse.chalmers.se/research/group/logic/book/)
[15]Simpler Easier. [Online]. Available: http://augustss.blogspot.ru/2007/10/simplereasierinrecentpapersimply.html(http://augustss.blogspot.ru/2007/10/simplereasierinrecentpapersimply.html)
[16] A. Bauer, How to implement dependent type theory I. [Online]. Available:http://math.andrej.com/2012/11/08/howtoimplementdependenttypetheoryi/(http://math.andrej.com/2012/11/08/howtoimplementdependenttypetheoryi/)
[17] A. Bauer, How to implement dependent type theory II. [Online]. Available:http://math.andrej.com/2012/11/11/howtoimplementdependenttypetheoryii/(http://math.andrej.com/2012/11/11/howtoimplementdependenttypetheoryii/)
[18] A. Bauer, How to implement dependent type theory III. [Online]. Available:http://math.andrej.com/2012/11/29/howtoimplementdependenttypetheoryiii/(http://math.andrej.com/2012/11/29/howtoimplementdependenttypetheoryiii/)
-
[19] J. Malakhovski, Functional Programming and Proof Checking Course. [Online]. Available:http://oxij.org/activity/itmo/fp/(http://oxij.org/activity/itmo/fp/)
[20] C. McBride and J. McKinna, The view from the left. [Online]. Available:http://strictlypositive.org/view.ps.gz(http://strictlypositive.org/view.ps.gz)
RelatednotesReinventingFormalLogic(/note/ReinventingFormalLogic/)
top related