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/)


Recommended